Traitement d'une image BMP

emrod Messages postés 9 Date d'inscription dimanche 9 avril 2006 Statut Membre Dernière intervention 13 mai 2006 - 9 avril 2006 à 11:12
BunoCS Messages postés 15475 Date d'inscription lundi 11 juillet 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 10 avril 2006 à 09:43
Salut, j'ai fait un programme, mais j'ai un petit problème, en effet il ne marche pas bien :)
Je lis une image BMP qui me sert de modèle, par exemple une forme rouge sur un fond noir. Je détermine dans cette image les niveaux de rouge, de vert, et de bleu minimum et maximum (par exemple rouge_min=120, rouge_max=230, etc...).
Je lis ensuite une autre image qui contient le modèle, et je cherche à détecter ce modèle dans l'image. Je regarde donc pour chaque pixel s'il appartient ou non aux couleurs du modèle (rouge situé entre rouge_min et rouge_max, etc...).
Je crée ensuite une autre image, en recopiant les pixels du modèle (reconnu dans l'image précédente), et en mettant à 0 les autres pixels (pixels noirs) de manière à n'avoir dans l'image résultat que le modèle, extrait de l'image précédente.

Le problème, c'est que j'ai l'impression que ça fait n'importe quoi, déjà j'obtient une image résultat toute noire, et en plus les niveaux de rouge, vert et bleu de l'image modèle ne sont pas bien définies (par exemple, si j'ai un modèle toute rouge, le programme me retourne aussi du bleu et du vert).
En fait, j'ouvre l'image avec fopen(), je lis d'abord l'entête (de taille 54 octets), puis je lis à chaque fois l'image avec getc(), mais je ne suis pas sûr que ça fonctionne comme je pense. Je pensais qu'en faisant comme ça, on obtient à chaque fois une valeur de bleu, de vert ou de rouge (successivement), donc si je fais 3 fois getc() j'obtient les 3 couleurs d'un pixel. Ca marche comme ça ?

Bon, voici mon programme pour mieux comprendre :

_________________________________________________________________________________________________

#include <stdio.h>

#define MODELE "modele.bmp" // image BMP 24 bits
#define IMAGE "image2.bmp" // image BMP 24 bits
#define RESULTAT "resultat.bmp"


int rouge_min=255;
int rouge_max=0;
int vert_min=255;
int vert_max=0;
int bleu_min=255;
int bleu_max=0;

int npix=0, npix_rouge=0, npix_vert=0, npix_bleu=0;

// définition des couleurs du modèle : niveaux (de rouge, vert et bleu) min et max du modèle (image MODELE)
void Modele(FILE *fp)
{
int i, a;
// lecture de l'entête
for(i=0;i<54;i++)
fgetc(fp);
i=0;

while((a=fgetc(fp))!=EOF)
{ if (a>0)
switch(i)
{ case 0 : // couleur bleue
{ if (a<=bleu_min)
bleu_min = a;
if (a>=bleu_max)
bleu_min = a;
npix_bleu++;
//printf("bleu : %d\n",a);
}
case 1 : // couleur verte
{ if (a<=vert_min)
vert_min = a;
if (a>=vert_max)
vert_max = a;
npix_vert++;
//printf("vert : %d\n",a);
}
case 2 : // couleur rouge
{ if (a<=rouge_min)
rouge_min = a;
if (a>=rouge_max)
rouge_max = a;
npix_rouge++;
//printf("rouge : %d\n",a);
}
}
i++;
if (i==3) i=0;

}

// si on n'a pas de pixels d'une couleur (rouge, vert, ou bleu), on définit le min et le max à 0
if (npix_rouge == 0)
{ rouge_min = 0;
rouge_max = 0;
}
if (npix_vert == 0)
{ vert_min = 0;
vert_max = 0;
}
if (npix_bleu == 0)
{ bleu_min = 0;
bleu_max = 0;
}
}



// reconnaissance du modèle dans l'image IMAGE et création de l'image RESULTAT contenant uniquement les pixels du modèle
void DetecteModele(FILE *fp1, FILE *fp2)
{
int i=0, rouge, vert, bleu;
// recopie de l'entete
for(i=0;i<54;i++)
fputc(fgetc(fp1),fp2);

//traitement
// lit les 3 couleurs d'un pixel, pour toute l'image IMAGE
while( ((bleu=fgetc(fp1))!=EOF) && ((vert=fgetc(fp1))!=EOF) && ((rouge=fgetc(fp1))!=EOF) )
{ //si les niveaux de rouge, vert et bleu du pixel appartiennent aux couleurs du modèle, on recopie le pixel
if ( (rouge >= rouge_min) && (rouge <= rouge_max) && (vert >= vert_min) && (vert <= vert_max) && (bleu >= bleu_min) && (bleu <= bleu_max) )
{ fputc(bleu,fp2);
fputc(vert,fp2);
fputc(rouge,fp2);
npix++;
}
// sinon on met un pixel noir
else
{
fputc(0,fp2);
fputc(0,fp2);
fputc(0,fp2);
}
}
}




main()
{
FILE *fp, *fp1, *fp2;
char c;

// détection modèle
fp=fopen(MODELE,"rb");
Modele(fp);

// reconnaissance modèle
fp1=fopen(IMAGE,"rb");
fp2=fopen(RESULTAT,"w+b");
DetecteModele(fp1,fp2);

// affiche les paramètres calculés (vérification)
printf("nombre de pixels du modele : %d\n",npix);
printf("nombre de pixels rouges : %d\n",npix_rouge);
printf("nombre de pixels verts : %d\n",npix_vert);
printf("nombre de pixels bleus : %d\n",npix_bleu);
printf("Niveau rouge min : %d\n",rouge_min);
printf("Niveau rouge max : %d\n",rouge_max);
printf("Niveau vert min : %d\n",vert_min);
printf("Niveau vert max : %d\n",vert_max);
printf("Niveau bleu min : %d\n",bleu_min);
printf("Niveau bleu max : %d\n",bleu_max);
scanf("%c",&c);

fclose(fp);
fclose(fp1);
fclose(fp2);
}

_________________________________________________________________________________________________

Voici les images que j'ai utilisé :
modele: http://img129.imageshack.us/img129/9092/modele1mm.png
image2: http://img129.imageshack.us/img129/371/image24zo.png
Ce sont des images assez simples, pour tester le programme.

Merci de votre aide :)

7 réponses

mogwai93 Messages postés 362 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 4 novembre 2023
9 avril 2006 à 15:15
1)

{ if (a<=bleu_min)


bleu_min = a;

if (a>=bleu_max)


bleu_min = a;

ce n'est pas plutot ?

{ if (a<=bleu_min)


bleu_min = a;

if (a>=bleu_max)


bleu_max = a;



2)

for(i=0;i<54;i++)

fgetc(fp);

i=0; // <--- pourquoi le reinitialiser ??



3) pour les performances, ne pas lire octet par octet

deja

tu peux lire par bloc :

- entete

- point (int R, int G, int B)

sinon, tu lis d'un coup le fichier et tu boucles sur le buffer



4) je n'ai pas tout regarder

mais il ne faudrait pas que tu boucles sur la hauteur et la largeur des 2 images ?

et regarder dans l'image la + grande, si la petite est comprise dans la grande ?
0
emrod Messages postés 9 Date d'inscription dimanche 9 avril 2006 Statut Membre Dernière intervention 13 mai 2006
9 avril 2006 à 16:08
Merci pour ta réponse, mais je vais encore t'embêter :)

1) Ok, merci, c'était une erreur de frappe.

2) En fait j'utilise i pour faire 2 choses. D'abord pour lire l'entête en un bloc. Puis je le remet à 0 car i permet de définir si je lis la couleur bleue (i=0), verte (i=1) ou rouge(i=2). C'est juste pour ne pas utiliser une variable en plus.

3) Je veux bien, mais comment faire pour lire l'image autrement ? A part utilser fgetc() ? Moi j'aimerais bien lire d'un coup 3 couleurs (pour avoir un pixel à chaque fois), mais je ne sais pas trop comment faire. C'est quel type de variable une couleur, c'est un octet, un entier, ... ?
Avant j'utilisais une méthode assez complexe (que je captais pas trop car je précise que l'info n'est pas ma spécialité, moi j'ai juste fait un peu de C et pas de C++ donc je ne connais pas bien toutes les fonctions et bibliothèques), et je lisais tout d'un coup et je le rangeais dans un buffer, puis je pouvais avoir chaque couleur en faisant un truc du style pixel.r, pixel.g, pixel.b, il n'y aurait pas un moyen de faire comme ça simplement (sans trop modifier mon programme) ?

4) Le problème c'est que je ne sais pas comment déterminer la hauteur et la largeur de mon image, il y a une fonction pour ça ? Ou c'est dans l'entête, et si oui comment l'avoir ?
Et puis, tu vois, la taille du modèle peut varier, car c'est un objet connu qu'on va rechercher dans une autre image (extraite d'une vidéo), et l'objet peut se trouver à n'importe quelle distance donc sa taille va varier. Et puis je devrais déterminer la distance de cet objet, j'aurais besoin de compter la hauteur de l'objet donc le nombre de pixels sur une même colonne (d'où l'utilité de connaitre la largeur et de la longueur de l'image).
0
mogwai93 Messages postés 362 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 4 novembre 2023
9 avril 2006 à 16:40
3) pour lire un fichier, tu peux utiliser fread

soit tu lis le fichier d'un coup

soit tu peux utiliser l'objet struct afin de definir une structure (R,
G, B) où R, G et B seront déclarés en CHAR ou BYTE (256
bits)



4) oui c'est stocké dans l'entete

soit tu te fais ta methode de lecture

soit tu utilises ce que Windows a déja :



HBITMAP FileToBitmap(LPCTSTR lpFileName)

{

HBITMAP hbmp = 0;

HANDLE hProcessHeap = GetProcessHeap();

HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);

if(hFile == INVALID_HANDLE_VALUE) return 0;

DWORD dwFileSize = GetFileSize(hFile, 0), dwRead;

LPVOID lpMem = HeapAlloc(hProcessHeap, 0, dwFileSize);

if(ReadFile(hFile, lpMem, dwFileSize, &dwRead, 0) && dwRead == dwFileSize)

hbmp = PictureToBitmap((LPBYTE)lpMem, dwFileSize);



HeapFree(hProcessHeap, 0, lpMem);



return hbmp;

}



puis

HBITMAP hBmpSrc=FileToBitmap("image.bmp");

BITMAP bmpInfo;

GetObject(hBmpSrc, sizeof(BITMAP), &bmpInfo);

SIZE Taille;

Taille.cx = bmpInfo.bmWidth;

Taille.cy = bmpInfo.bmHeight;
0
emrod Messages postés 9 Date d'inscription dimanche 9 avril 2006 Statut Membre Dernière intervention 13 mai 2006
9 avril 2006 à 19:38
Merci pour ta réponse, mais il faut rajouter des bibliothèques (je sais pas si c'est ça le nom, mais les trucs du style #include <stdio.h> ), et je sais pas lesquelles.
Est-ce qu'il y a un moyen (un site par exemple) de trouver quelle bibliothèque il faut ajouter pour avoir le droit d'utiliser une certaine fonction ?
Là j'ai rajouté windows.h, mais PictureToBitmap ne marche pas, qu'est-ce qu'il faut rajouter d'autre ? (j'ai cherché mais j'ai pas trouvé sur internet). C'est surtout ça mon problème avec le C++, il y a trop de bibliothèques et j'en connais presque aucune (à part celles de base)...
0

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

Posez votre question
mogwai93 Messages postés 362 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 4 novembre 2023
9 avril 2006 à 21:41
#include <olectl.h>



HBITMAP PictureToBitmap(LPBYTE pmem, DWORD nSize)

{

HRESULT hr;

CoInitialize(0);

HBITMAP hbmp_dst = 0;

HGLOBAL hgbl =(HGLOBAL)GlobalAlloc(GMEM_FIXED, nSize);



memcpy(hgbl, pmem, nSize);



IStream* stream = 0;

hr = CreateStreamOnHGlobal(hgbl, TRUE, &stream);

if(!SUCCEEDED(hr) || !stream)

{

stream->Release();

GlobalFree(hgbl);

CoUninitialize();

return NULL;

//goto errPicture;

}



IPicture* picture = 0;

hr = OleLoadPicture(stream, nSize, 0, IID_IPicture, (void**)&picture);

if(!SUCCEEDED(hr) || !picture)

{

stream->Release();

GlobalFree(hgbl);

CoUninitialize();

return NULL;

//goto errPicture;

}



HBITMAP hbmp_src;

picture->get_Handle((OLE_HANDLE *)&hbmp_src);

if(!SUCCEEDED(hr) || !picture)

{

picture->Release();

stream->Release();

GlobalFree(hgbl);

CoUninitialize();

return NULL;

//goto errHandle;

}



BITMAP bmp;

GetObject(hbmp_src, sizeof bmp, &bmp);

hbmp_dst = (HBITMAP)CopyImage(hbmp_src, IMAGE_BITMAP, 0, 0, 0);



errHandle:

picture->Release();

errPicture:

stream->Release();

errStream:

GlobalFree(hgbl);

CoUninitialize();

return hbmp_dst;

}





et rajouter dans l'edition des liens

pour devc++ :

libolepro32.a

libole32.a

libuuid.a

(pour visual c++, ca doit etre la meme chose, sans le 'a' final)





sauf que ce code fonctionne pour les bmp, gif, jpg

donc on doit pouvoir simplifier, si tu n'utilises que du bmp..



tu peux tjs regarder cette source :

http://www.cppfrance.com/codes/LOADER-BMP-TRAITEMENT_33150.aspx
0
emrod Messages postés 9 Date d'inscription dimanche 9 avril 2006 Statut Membre Dernière intervention 13 mai 2006
10 avril 2006 à 00:10
Merci pour ta réponse (je savais pas pour les liens à rajouter), mais j'ai trouvé quelque chose de plus simple pour avoir la largeur et la hauteur de l'image (c'est dans l'entête) :

BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader;
DWORD width, height;
fread (&fileheader,14,1,fp);
fread (&infoheader,40,1,fp);
width = infoheader.biWidth; // largeur de l'image
height = infoheader.biHeight; // hauteur de l'image

Bon, là j'ai toujours des problèmes avec mon programme, mais je vais essayer d'utiliser ce que j'ai trouvé pour le modifier, en espérant que ça marche (j'essaie aussi de m'inspirer d'autres programmes).
Je remettrai un message si j'ai encore besoin d'aide.
Merci en tout cas pour ton aide !
0
BunoCS Messages postés 15475 Date d'inscription lundi 11 juillet 2005 Statut Modérateur Dernière intervention 23 avril 2024 103
10 avril 2006 à 09:43
Pour un exemple de traitement de fichiers BMP, voir ma source:
http://www.cppfrance.com/codes/LOADER-BMP-TRAITEMENT_33150.aspx

Buno
----------------------------------------
L'urgent est fait, l'impossible est en cours. Pour les miracles, prévoir un délai...
Le site de mon mariage
0
Rejoignez-nous