[C] Pb avec analyse d'images à niveau de gris

Fermé
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 - 11 oct. 2006 à 15:05
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 - 17 oct. 2006 à 14:49
Bonjour

J'ai besoin de programmer quelque chose en C (seul langage que je connaisse suffisamment pour faire ça).

--------------------------------
Explications du programme :
--------------------------------

Le programme doit ouvrir des images dans un dossier, les parcourir et selon la couleur du pixel, il dit si c'est du fer ou du carbone (pour faire ensuite de la modélisation 3D).

Le programme parcourt donc l'image, tous les "spacing" (ici 3) pixels, il analyse le pixel, en prend les coordonnées, enregistre cela dans différents fichiers textes.

Le programme ne doit pas analyser le matériaux de la dernière image ou des bords, il doit juste en extraire les coordonnées.

Un petit algo :

*Si on est à un pixel multiple de "spacing",( ici 3)

- si ce n'est pas la dernière image et si on n'est pas au bord (en bas ou à droite) alors on analyse le matériau, on enregistre les coordonnées

- sinon on enregistre juste les coordonnées sans enregistrer le matériau

*Sinon on poursuit jusqu'à un multiple de 3

-------------------------
Problèmes rencontrés
-------------------------

Le programme tourne bien, pas de plantage mais n'analyse pas bien les images.
Sur le bord supérieur de l'image, il part un peu en sucette si je puis dire, il considère toute une partie bizarrement (le mieux est de voir les exemples sur le serveur que je donne à la fin du message)

L'image originale est 001.bmp, l'image finale analysée est 001.bmpBIN.bmp

-------------------------------
Source + Images exemples
-------------------------------

Voici le répertoire pour la source et quelques images analysées :
willie.sharp.free.fr/APiMaDes

Si quelqu'un avait l'amabilité d'analyser mon code source (qui est plutôt long je sais) et trouver soit mon erreur pour qu'il analyse correctement cette bande du haut, soit trouver une parade pour la zapper (sans pour autant changer les coordonnées ou alors les adapter pour qu'elles commencent toujours à 0), il est le bienvenu !


Merci de m'aider, c'est très important pour mon Studienarbeit (diplome de fin d'étude d'ingénieur en génie des matériaux, rien à voir avec la programmation)

Bergie
A voir également:

11 réponses

Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
12 oct. 2006 à 09:41
En fait, peu importe l'image analysée (toute noire, toute blanche, toute grise ...) la même erreur revient, exactement la même, la bande du haut devient une sorte de dégradé gris, alors que je n'enregistre pas du tout de gris !

Si vous pouviez m'aider, ca me sauverait presque 2 mois de travail déjà accompli ...

Merci
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
13 oct. 2006 à 15:00
J'ai reparcouru mon code source (après l'avoir imprimé, histoire d'avoir une vue plus aisée du contenu complet) avec l'aide de ma tutrice qui voulait savoir ce que mon programme faisait et on a découvert qques erreurs de programmation ou de logique (après 3 jours de recherches à me creuser la tête sans jamais rien trouver).

1er problème :
Lorsque je "zappais" les bordures, la valeur de pixIdx n'était pas incrémentée, donc quand il lisait les pixels suivants, il lisait en fait au mauvais endroit (peut etre ... je n'en étais pas vraiment convaincu)

2ème problème :
Une parenthèse avait été remplacée par un signe "-" dans un if, ce qui donnait : si ((colIdx < - height - height%spacing )- spacing) au lieu de si ( colIdx < (height - height%spacing)-spacing)

3ème problème :
Après avoir remarqué ces erreurs quand même non négligeables, il a fallu trouver une autre source, et pourquoi ne pas directement chercher l'erreur non pas dans le programme, mais dans les images en elles mêmes !?
J'ai créé des images à partir de PAINT (tout simplement) avec du noir et blanc uniquement (mais toujours codée en 256 couleurs) et la cela marchait parfaitement, pas de bande bizarre tout en haut.
J'ai donc récupéré toutes les caractéristiques des images (résolution verticale et horizontale, trames, codage des couleurs) et je me suis aperçu que les images qui étaient correctement analysées devait avoir une certaine résolution de 32 pixels / cm alors que mes images de microscope en avait dans les 37,XX / cm
En les mettant en 32 pixels/cm, je n'ai plus cette foutue barre du haut en dégradé.

Le programme tourne sans problème en ce qui concerne la bordure du haut, mais il reste cependant encore quelques problèmes mineurs je pense.
Certains pixels ne sont pas analysés correctement et la moyenne des pixels est donc fausse, ce qui donne des résultats un peu bizarres, comme des points blancs en pleins milieu d'un entoruga de pixel noir, mais cela est sans doute une erreur de prog que je devrais trouver + facilement que les erreurs précédentes.

Merci pour votre aide, si vous voulez trouver mes erreurs de prog, je mets ma nouvelle source à la même adresse que l'ancienne (j'écrase l'ancienne) et pareil pour les images, il y a les originales et les "bizarres" obtenues.
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
16 oct. 2006 à 10:08
Je vois que ça ne passionne pas mon topic, mais bon, j'en ai besoin quand même ...

J'ai fait des essais en prenant des images test (certaines que blanches, d'autres que noires, d'autres quadrillées) et j'ai testé l'influence de la taille des images, du rapport largeur / hauteur et j'ai remarqué que la largeur devait être comprise entre 4 * la hauteur et la moitié de la hauteur :

4 x hauteur > largeur > hauteur / 2

Donc je sais maintenant (à priori) comment éviter les fameux carrés et la bande grise en haut de mes images.

Maintenant l'autre problème est l'interprétation de certaines images (voir image micro001 et micro001BIN sur le serveur willie.sharp.free.fr/APiMaDes/)
Les deux images devraient être quasiment identiques (à quelques pixels près) mais naturellement, les pixels qui changent sur l'image micro001BIN ne sont bien sûr pas les bons !

Je vous en prie, essayez de m'aider à résoudre mon pb, c'est super important pour mes études et pour avancer dans mon projet (la programmation n'est qu'une partie infime et je n'ai pas de formation de programmeur.)

Merci de m'aider
0
Il me semble detecter plusieurs erreurs.

1) pixMed=pixMed+bitmap[pixIdx+x+y*bmpf->width];

Là il faut en fait parcourir tous les pixels dans un voisinage (spacing x spacing) en bas à gauche (l'axe des y est traditionnalement tourné vers le bas pour les images, (0,0) etant le coin supérieur gauche) du point de coordonnées (colIdx, pixIdx)

2) Il faut donc corriger comme suit:
pixMed=pixMed+bitmap[(colIdx+x)+(y+rowIdx)*bmpf->width];

Ensuite il faut s'assurer que (colIdx+x) < largeur d'image et (y+rowIdx) < hauteur d'image EN TOUTE CIRCONSTANCE.
Pour cela il faut arrêter le balayage (colIdx,rowIdx) avant qu'il arrive dans les bordures droite et bas de largeur "spacing".

Pour cela il faut modifier les lignes come suit:
for (colIdx=0; colIdx<(bmpf->width-spacing); colIdx++)
et
for (rowIdx=0; rowIdx<(bmpf->height-spacing); rowIdx++)

(+ enlever le test avec les modulos qui ne sert à rien)

3) Le calcul de pixMed donne la SOMME des pixels dans le noyaux (spacing,spacing) et non la moyenne (ne pas oublier de diviser par spacing*spacing s'il le faut).
D'ailleurs il ne s'agit pas de median (médiane) mais plutot de average (moyenne) Les deux valeurs n'ayant pas du tout le meme sens en traitement d'image.

4) Enregistrer la valeur binarisée de la façon suivante qui est homogene avec la facond de lire l'image:
bitmap[colIdx+rowIdx*bmpf->width] = ...

5) Enfin s'assurer que les pixels d'une ligne sont bien contigus
dans le tableau bitmap[] sinon les formules du 2) et 4) devraient être inversées en lignes/colonnes:
bitmap[colIdx*bmpf->height+rowIdx]

Voila pour commencer...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
A la relecture, je m'aperçois de coquilles:
1) Lire "en bas à droite" et non "en bas à gauche"
5) J'ai écris ça parceque ca fait un bail que je n'ais plus pratiqué le C++ et les bitmaps, mais je me souvient vaguement que ça pouvait pouver poser des problèmes. A vérifier.
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
16 oct. 2006 à 16:59
Bonjour

Merci de ton aide.
La source online n'est apparemment pas la plus récente que j'ai sur mon PC, mais c'est pas grave, cela revient à peu près au même.
J'ai modifié les trucs que tu m'as conseillé de changer mais cela revient exactement au même.

1. Alors donc les pixels des images sont numérotés à partir du bas à droite ? (si c'est le cas, merci, ca va m'aider pour les coordonnées de mes repères après)
Je ne comprends cependant pas pourquoi pixMed=pixMed+bitmap[pixIdx+x+y*bmpf->width] ne convient pas et qu'il faut le remplacer par pixMed=pixMed+bitmap[(colIdx+x)+(y+rowIdx)*bmpf->width]
Dans les deux cas, j'obtiens le même résultat sur les images.

2. Le test avec le modulo me sert je pense :
Je ne dois enregistrer qu'un pixel sur 3 en x et y (donc un pixel sur 9), il faut donc que je fasse mon test avec le modulo.
En plus, si on est au bord (dernier carré de 3x3 possible dans l'image) et/ou sur la dernière image , je ne dois enregistrer que les coordonnées et non enregistrer la moyenne et tester le matériau, donc si je ne me trompe pas, ce test est bien utile

3. J'avais déjà changé la variable pixMed en faisant bien attention qu'elle soit divisée, erreur vraiment minable, je l'affichais bien mais j'ai oublié de l'affecter :)

4. Sur la façon d'enregistrer, je ne la comprends pas (normal, vu que je ne comprends pas déjà le point 1.)

5. dans ton point 5., tu dis de faire attention à quoi exactement ? Je ne te suis pas vraiment ...

Je mets à jour la source sur le serveur, je mets les images que j'obtiens et j'encadre en rouge qques pixels qui devraient être de l'autre couleur, afin que tout le monde comprenne ce que je veux dire :)

Merci beaucoup de t'intéresser à ce pb, on va surement trouver une solution.

(Je précise à tous que j'ai essayé en compilant et en analysant sous linux et cela donne la même chose, cela ne vient donc pas de l'environnement Windows)
0
Bonjour,

1) Effectivement, traditionnellement le pixel en haut à gauche est (0,0) et l'axe des y est dirigé vers le bas.
Le format bmp est assez ancien (il date des debuts de windows il me semble) et les choix techniques d'alors ne semblent pas 100% logique aujourd'hui. D'où ma remarque du 5): tu dois t'assurer que les pixels sont bien rangés en mémoire dans l'ordre que tu supposes, à savoir: les pixels d'une meme LIGNE (et non d'une même COLONNE) dans des cases consecutives du tableau bitmap[]. C'est simple à vérifier le traitement se passerait a peu près bien, mais le resultat serait inversé en x et y.

Ta façon de passer des coordonnées (x,y) à l'index dans le tableau suppose que tu comptabilise parfaitement tous les pixels possibles dans pixIdx au fur et à mesure de ta progression. Ca peut marcher mais c'est peu fiable, surtout si tu décide de ne pas parcourir tous les pixels (en en sautant 1/3 par exemple). La méthode que je t'ai donnée est sensé être toujours exacte à condition que les pixels soient rangés dans le bon ordre (cf+haut 5) ).

Dernier point que je n'avais pas évoqué, tu fais parcourir l'image à ton point de réference (colIdx,rowIdx) mais le noyau (le carré sur lequel tu fais la moyenne) n'est pas centré sur le point de référence, comme c'est l'habitude. Ca explique pourquoi les point noir anormaux sont toujours dans du blanc en bas à gauche d'une étendue noire et les points blanc anormaux dans du noir en bas à gauche d'une étendue blanche.
Pour cela il faudrait que tu fasse les boucle sur x et y sur l'intervalle [-spacing/2,spacing/2] (attention au arrondis!) plutôt que [0,spacing[ et que tu utilises les formules du 1) et 4).

Attention, ton test sur les modulos devient faux.
Il suffit alors que tu modifie le parcours de ton point de réference de la façon suivante:

for (rowIdx=spacing/2; rowIdx<(bmpf->height-spacing/2); rowIdx+=spacing)
...
for (colIdx=spacing/2; colIdx<(bmpf->width-spacing/2); colIdx+=spacing)


Ainsi rowIdx va parcourir l'intervalle [spacing/2,hauteur-spacing/2[
ce qui permet à rowIdx+y de parcourir l'intervalle [0,hauteur[, donc de rester dans l'image.
Idem pour colidx.

De plus rowIdx+=spacing va permettre de "sauter" 'spacing' pixels sur l'intervalle.

Attention, Si tu modifies le parcours du point de référence ainsi, la comptabilité des pixels dans pixIdx sera faussée
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
17 oct. 2006 à 09:41
Bonjour

Merci de la réponse

Je comprends bien maintenant, mais il reste un détail un peu flou.

Je comprends bien que ce soit toujours plus "correct" de mettre le noyau sur le point de référence, mais je ne vois pas enquoi ma méthode me ferait avoir des points faussés, vu que mes pixels blancs apparaissent dans un environnement complètement noir, il devrait rester noir quoi qu'il se passe, non ?

A propos des arrondis justement, comment être sûr que cela se passera bien, dans mon cas, j'utilise 3 pour mes tests, mais après le programme doit servir à tout le labo et jene sais pas quels pas les autres personnes vont utiliser. Si on considère que le centre doit être la référence, il faut donc des pas impairs supérieurs à 1.

Et à paropos de l'ordre de spixels, apparemment ça a l'air d'aller, sinon tu veux dire queje me retrouverais avec la même image mais avec rotation de 90° en gros c'est ça ? Or icije recois quasiment la même image.
Merci de me sortir du brouillard :)
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
17 oct. 2006 à 11:31
Bonjour

Bon rectification faite, cela ne fonctionne pas ...Je te donne sur mon serveur comem d'habitude ce que cela donne sur les images :
Dans ce cas précis, image toute blanche qui deviet blanche avec points noirs, ce qui est loin du résultat.

(En fait, si je n'essaye pas d'analyser le matériaux, donc si je zappe toute la partie analyse, cela fonctionne, mais si j'essaye de faire l'analyse de la moyenne etc, il croit que tout est noir apparemment !)

Merci
0
En fait il reste un petit probleme:
Quand tu modifies la valeur du pixel de référence (par exemple en mettant 255 dedans), ce pixel fait encore partie du noyau au déplacement suivant, ce qui perturbe le calcul de la moyenne.

Pour éviter cela il faut travailler avec 2 images: une source que tu ne modifies pas et une destination que tu modifies.

(...)
// Pixel goes through the whole image pixel by pixel
bmpf = ReadBMPfile(Current_File);
bitmap = bmpf->bitmap_data ;

//alaink: On cree un fichier destination par duplication
WriteBMPfile(strcat(Current_File,"BINTEMP.bmp"),bmpf );
//alaink: ouvre le fichier destination
bmpfdest = ReadBMPfile(Current_File);
bitmapdest = bmpfdest->bitmap_data ;


// Analysing rows
for (rowIdx=(spacing-1)/2; rowIdx<(bmpf->height-(spacing-1)/2); rowIdx+=spacing)
{
// Analysing Columns
for (colIdx=(spacing-1)/2; colIdx<(bmpf->width-(spacing-1)/2); colIdx+=spacing)
{
// Material analysis if it is not the last image and not at the border of the current image
if ((depthIdx+1)<File_Number)
{
// Calculate the median in the spacing * spacing box
pixMed=0;
for (x=-(spacing-1)/2; x<=(spacing-1)/2; x++)
{
for (y=-(spacing-1)/2; y<=(spacing-1)/2; y++)
{
//printf("Round X=%d Y=%d Width=%d Y*Width=%d pixIdx=%ld ",x,y,bmpf->width,y*bmpf->width,pixIdx+x+y*bmpf->width);
pixMed=pixMed+bitmap[(colIdx+x)+(y+rowIdx)*bmpf->width];
//printf("Value %d\n",bitmap[pixIdx+x+y*bmpf->width]);
}
}
pixMed = pixMed / (spacing * spacing);
//printf("Median %lf\n",pixMed);

// Determination of material type
if (pixMed > threshold)
{
//alaink:On ecrit dans le fichier dest
bitmapdest[colIdx+rowIdx*bmpf->width] = 255;
fprintf(Iron,"%ld, ",nodIdx);
}
else
{
//alaink:On ecrit dans le fichier dest
bitmapdest[colIdx+rowIdx*bmpf->width] = 0;
fprintf(Grafit,"%ld, ",nodIdx);
}
// Nodes file update
fprintf(Nodes,"%ld, %ld., %ld., %ld.\n",nodIdx,depthIdx,colIdx,rowIdx);

nodIdx++;
}
// If last image or border, just create Nodes without analysing the material
else
{
// Nodes file update
fprintf(Nodes,"%ld, %ld., %ld., %ld.\n",nodIdx,depthIdx,colIdx,rowIdx);
nodIdx++;
}
} // End Columns
} //End Rows

depthIdx++;
// Saves the binarised image
//WriteBMPfile(strcat(Current_File,"BIN.bmp"),bitmap );
//alaink: on enregistre le fichier dest
WriteBMPfile(strcat(Current_File,"BIN.bmp"),bitmapdest );
bitmpfdest = DelBMPFile(bitmapdest) ;

bmpf = DelBMPFile(bmpf) ;
}// End While

(...)
0
Bergie Messages postés 139 Date d'inscription mercredi 27 septembre 2006 Statut Membre Dernière intervention 7 mars 2009 7
17 oct. 2006 à 14:49
Rebonjour

Désolé de te prendre la tête avec ça, je te remercie de ton aide, c'est très apréciable.

Cela fonctionne mieux avec les images toute blanche (le petit carré blanc par exemple) mais cela ne fonctionne toujours pas à 100 % avec mes fameuses images microscopiques.

Je te mets deux images que je dois analyser micro001 et micro002, essaye de lancer le programme toi même pour voir ce que cela donne sur ton ordi, mais chez moi, ce la donne toujours des carrés blancs et noirs mal placés...

HELP !!
0