Allocation dynamique 3 dimensions [Résolu]

Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 13 sept. 2004 à 08:15 - Dernière réponse :
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 16 sept. 2004 à 22:57
Bonsoir,

J'alloue la mémoire d'un tableau contenant les pixels d'une image. Si je déclare classiquement mon tableau ( ex: image[512][1024][3] ) tout se passe bien, et j'arrive à mapper mon objet...

mais avec le code suivant, ça se complique :
l'image résultante est complètement brouillée...
pourtant l'allocation se passe sans erreur (testé) et je désalloue
(avec free, ou delete selon le cas c ou c++).
Est-ce un probleme d'initialisation de mon tableau ?
Texture est une variable globale, et l'allocation dynamique est faite dans une fonction secondaire.

Merci pour toute info,
Bonne soirée, et douce nuit.

Gil

/////////////////// ALLOC DYNAMIQUE /////////////////////

width = cinfo.image_width;
height = cinfo.image_height;
int dim_gris = width*height;
int dim_rgb = width*height*3;

/////////////////// ESSAI EN C ////////////////////////
/*
texture = (unsigned char ***)calloc(height,sizeof(unsigned char **));
if (texture == NULL) exit (1);

for ( int i = 0; i < height; i++ )
{
texture[i] = (unsigned char **)calloc(width,sizeof(unsigned char *));
if (texture[i] == NULL) exit (1);
}

for ( i = 0; i < height; i++ )
for ( j = 0; j < width; j++ )
{
texture[i][j] = (unsigned char *)calloc(3,sizeof(unsigned char ));
if (texture[i][j] == NULL) exit (1);
}
*/

/////////////////////// ESSAI C++ //////////////////////////

texture = new unsigned char **[height];

for ( i=0; i<height; i++)
texture[i] = new unsigned char *[width];

for ( i=0; i<height; i++ )
for ( j=0; j<width; j++ )
texture[i][j] = new unsigned char [3];

////////////////////////// FIN //////////////////////
Afficher la suite 

Votre réponse

12 réponses

Meilleure réponse
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 14 sept. 2004 à 14:24
3
Merci
gluBuild2DMipmaps attend pas un tableau de 3 dimension mais un pointeur sur un buffer contenant les donnée (sinon ausun interet fonctionnel et impossible de passer en parametre un tableau a n dimension si les n-1 dernieres dimension ne sont pas fixées), si ca marche avec un tableau 3 dimension c'est parce que les elements sont bien entendu contigue

"Peut-il ne pas y avoir contiguité quand même ?"

oui, reli un cours sur pointeur et tableau c'est important si tu veux pas te planter par la suite

tu vera comment sont ordonnée les element dans un tableau multidimensionnel (qui est en fait un tableau de tableau...) mais ca reste un zone contigue, la seul difference avec un tableau unidimensionnel c'est que tu peux indexer les elements sur plusieurs dimensions

pour l'allocation dynamique, tu as fais une erreur malheureusement classique en croyant pouvoir allouer un tableau 3d a partir d'un pointeur de pointeur de pointeur (***texture)

par exemple si tu voulais allouer dynamiquement un tableau 2d de 20*50 par exemple, tu aurais fais

int **tab;

tab = new int*[20];for( unsigned i 0; i < 20; i ++ ) tab[i] new int[50];

seulement la les elements ne sont pas contigus car tu as d'abord allouer un tableau de 20 pointeur (int*), puis tu alloue pour chacun de ces pinteur une zone de 50 int qui est certe contigu, mais les zones ne le sont pas entre elle

d'ailleur pour acceder a un elements tu dois faire un double deferencement ce qui traduis bien le fais que les données sont eparpillée en memoire par segment de 50 elements

par exemple pour acceder a l'element , (5,6) tu ferais
tab[5][6] = 5;

mais c'est dans ce cas equivalent a *(*(tab + 5) + 6) 5;> double deferencement

comme je l'ai dis, la bonne facon d'allouer un tableau a n dimension si tu connais les n-1 derniere dimensions c'est

int (*tab)[50];

tab = new int[20][50];

et la aucun probleme

si tu ne connais pas toutes les dimensions, alors alloue un tableau unidimensionel et arrange toi pour l'indexer sur plusieurs dimensions (cf l'exemple de mon post precedent)

Merci cs_djl 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 cs_djl
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 13 sept. 2004 à 08:36
0
Merci
qu'est ce que tu veux faire avec un tableau de pointeur de pointeur... ?

ce qui compte c'est comment doivent etre ordonnées les données en memoire

pour preserver la contiguite des elements, alloue un tableau de tableau

unsigned char (*texture)[3];

texture = new unsigned char [width*height][3];
...
Commenter la réponse de cs_djl
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 13 sept. 2004 à 10:57
0
Merci
à terme j'ai besoin d'un tableau 3 dim....

unsigned char (**texture)[3];
texture = new unsigned char [height][width][3];

erreur à la compil :
cannot convert unsigned char (*)[((width-1) + 1)] to unsigned char (**)[3]
Commenter la réponse de gilimcce
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 13 sept. 2004 à 11:26
0
Merci
aussi....

unsigned char (**texture)[3];

texture = new unsigned char *[height][3];
for ( i=0; i<height; i++)
texture[i] = new unsigned char [width][3];

erreur compil :
cannot convert unsigned char* (*)[3] to unsigned cahr (**)[3]
(c'est la 1ere allocation qui declenche cette erreur)
Commenter la réponse de gilimcce
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 13 sept. 2004 à 18:53
0
Merci
pas unsigned char (**texture)[3];

toujours unsigned char (*texture)[...][3]; si tu veux presever la contiguité des elements

ta compris pourquoi le type d'allocation que tu fais dans ton 1er post fou tou en l'air ?

pour allouer un tableau a n dimension dynamiquement, seul la premiere doit etre inconnu (non resolu a la compilation)

dans ton cas, la largeur et la hauteur son inconnu, tu es donc obliger de faire

unsigned char (*texture)[3];

texture = new unsigned char [width*height][3];

// pour acceder a l'element [i][j][0] par exemple

for(size_t i = 0; i < height; i ++ )
for(size_t j = 0; j < width; j ++ )
texture[ i * width + j ][0] = ...

// pour liberer
delete[] texture;
Commenter la réponse de cs_djl
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 14 sept. 2004 à 11:49
0
Merci
Le souci est qu'une de mes fonctions sous OpenGL recquiert un tableau 3D en paramètre :

gluBuild2DMipmaps(...,texture)

Si j'imprime le contenu de texture alloué dans le dur [720][1440][3] et alloué dynamiquement comme ds le 1er post, j'obtiens exactement les mêmes valeurs aux mêmes cases. Peut-il ne pas y avoir contiguité quand même ?

En l'occurence, j'utilise gluBuil2DMipmaps au lieu de glTexImage2D car mon jpeg n'a pas de dimensions en puissance de 2. gluBuild2DMipmaps se charge de redimmensionner.

Voili voilou
Commenter la réponse de gilimcce
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 14 sept. 2004 à 16:27
0
Merci
Bon, si je te dis que ça marche...
Etonné ?

Dernière mise au point :
Lors de la déclaration et de la définition de ma fonction
"loadJpegImage" où texture est rempli puis
retourné au programme principal, j'ai une rreur à la compilation :

je déclare ma fonction en en-tete de cette façon :
unsigned char *[3] loadJpegImage(char *fichier);

et la défini ainsi :
unsigned char (*t)[3] loadJpegImage(char *fichier)
{
......
.......
}

J'imagine que c'est mal écrit....
Concernant la non contiguité, mon prof m'avait prévenu
qu'il y aurait un problème de ce genre avec mon allocation...

Merci de ne pas en etre resté là dans tes observations !
Commenter la réponse de gilimcce
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 14 sept. 2004 à 16:39
0
Merci
En, fait, et pour etre plus clair :

"loadJpegImage" retourne texture
qui est un unsigned char (*)[3]

et si je declare et defini cette fonction :
unsigned char (*)[3] loadJpegImage(......)
{
...
...
}

j'ai une erreur à la compil
Je suis Sincèrement désolé.
Commenter la réponse de gilimcce
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 14 sept. 2004 à 17:03
0
Merci
en principe on retourne un pointeur sur le pemier element (multidimensionnel ou pas ca reste transparent)

unsigned char *loadJpegImage(...)
{

...
return (unsigned char *)texture;
}

theoriquement il y a une synthaxe pour ca, mais ce n'est pas necessiare

peut etre

(unsigned char *)[3] loadJpegImage(......) ?

sinon vasi a coup de typedef :)

typedef unsigned char *pPix [3];

pPix loadJpegImage(......);

mais globalement je pense pas que le prototype de ta fonction soit le design adequate, en principe quand on charge une texture (qqsoit le format de l'image) on recupere un pointeur sur les données, la largeur et la hauteur

moi je ferais

int loadJpegImage( char *buffer, size_t *width, size_t *height );

ou si tu prefere (mais ca reste strictement identique)

int loadJpegImage( unsigned char *buffer[3], size_t *width, size_t *height );

la valeur retour sert bien sur pour indiquer une eventuelle erreur
Commenter la réponse de cs_djl
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 15 sept. 2004 à 12:14
0
Merci
Bon...
Tout semblait etre bien parti...
Mais, le mappage ne se fait plus, a la place j'ai
"free(): invalid pointer 0x404abfd8!"

J'ai testé les adresses memoire des differents tableaux,
aucune ne correspond a celle generant l'erreur,
a moins qu'il ne s'agisse pas de l'adresse de l'element [0][0].

Bon, en attendant peut etre une lumineuse revelation du forum,
je vais afficher chaque adresse des elements de texture, l'erreur semble
venir de la.

Aussi, voilà le code, au cas zou...
Foutus pointeurs.

//////////////////// CHARGEMENT DE L'IMAGE//////////////////////////

int loadJpegImage(char *fichier, unsigned char (*texture)[3], int *Pt_width, int *Pt_height)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *file;
unsigned char *ligne;
int i,j;

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);

if ((file=fopen(fichier,"rb"))==NULL)
{
char phr[100]; vidage(phr,100);

strcat(phr,"Erreur : impossible d'ouvrir le fichier ");
strcat(phr,VAR);
strcat(phr,".jpg\n");

fprintf(stderr,phr);
vidage(phr,100);
exit(1);
}

jpeg_stdio_src(&cinfo, file);
jpeg_read_header(&cinfo, TRUE);

int t_width = cinfo.image_width;
int t_height = cinfo.image_height;

Pt_width = &(t_width);
Pt_height = &(t_height);

int dim_gris = (t_width * t_height);
int dim_rgb = (t_width * t_height * 3);

unsigned char *image_gris = new unsigned char[dim_gris];
if (image_gris == NULL){cout<<endl<<"Erreur d'allocation image_gris"<<endl;exit(0);}
unsigned char *image_rgb = new unsigned char[dim_rgb];
if (image_rgb == NULL){cout<<endl<<"Erreur d'allocation image_rgb"<<endl;exit(0);}
texture = new unsigned char [dim_gris][3];
if (texture == NULL){cout<<endl<<"Erreur d'allocation texture"<<endl;exit(0);}

if (cinfo.jpeg_color_space==JCS_GRAYSCALE)
{
jpeg_start_decompress(&cinfo);
ligne=image_gris;

while (cinfo.output_scanline<cinfo.output_height)
{
ligne=image_gris+t_width*cinfo.output_scanline;
jpeg_read_scanlines(&cinfo,&ligne,1);
}

jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

// rearrangement de l'image scannee dans le tableau de texture 3D
// ici nous sommes en niveau de gris, donc on copie le meme octet dans
// chacune des 3 cases RGB
// merci � jonatahn

for (i=0;i<t_height;i++)
for (j=0;j<t_width;j++)
{
texture[i*t_width+j][0]=image_gris[i*t_width+j];
texture[i*t_width+j][1]=image_gris[i*t_width+j];
texture[i*t_width+j][2]=image_gris[i*t_width+j];
}

}
else
{
jpeg_start_decompress(&cinfo);
ligne=image_rgb;
while (cinfo.output_scanline<cinfo.output_height)
{
ligne=image_rgb+3*t_width*cinfo.output_scanline;
jpeg_read_scanlines(&cinfo,&ligne,1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

// rearrangement de l'imtage scannee dans le tableau de texture 3D

for (i=0;i<t_height;i++)
for (j=0;j<t_width;j++)
{
texture[i*t_width*3+j*3][0]=image_rgb[i*t_width*3+j*3];
texture[i*t_width*3+j*3][1]=image_rgb[i*t_width*3+j*3+1];
texture[i*t_width*3+j*3][2]=image_rgb[i*t_width*3+j*3+2];
}
}

delete image_gris;
delete image_rgb;
return (0);
}

//////////////// VIDAGE DE TEXTURE //////////////////////

void vidage_malloc(unsigned char (*tab)[3])
{
delete[] tab;
}

//////////// NOTES //////////////////////////////

Je fait appel a cette fonction de vidage dans le main, juste avant la boucle glut.
Commenter la réponse de gilimcce
Messages postés
33
Date d'inscription
jeudi 2 septembre 2004
Dernière intervention
27 septembre 2004
- 15 sept. 2004 à 17:06
0
Merci
Voila qq chose de plus explicite peut etre.
Meme avec de l'aide, on reste sans sollution.

l'erreur est :

Freeing inexistant memory in deimos_OGL.cpp at line 285.
c'est a dire dans la fonction suivante :

void vidage_malloc(unsigned char *tab)
{
free(tab);

#ifdef PERFORM_MEMORY_CHEKS
MEMCHEK_reportLeak();
#endif
}

Les 3 dernieres lignes font appel a une routine detectant
les erreurs memoires, fuites.....

Cette fonction est appelée juste avant 'glutMainLoop()' :

vidage_malloc(text);

text est un pointeur sur unsigned char (ou sur (*)[3], on a essayé les 2 comme tu m'avais dit) et est passé en parametre dans la fonction loadJpegImage :

loadJpegImage(chemin, text, &width, &height);
chemin est l'adresse de l'image chargee.
dans le corps de cette fonction est declare dynamiquement un tableau d'unsigned char :

unsigned char *image_gris = (unsigned char)malloc(dim_gris*sizeof(unsigned char));
....
.....
texture=image_gris;

Donc text a bien une adresse pointant sur image_gris ?
En fait, autre souci, le mappage ne se fait plus, alors que la désallocation
ne devrait pas influer puisque venant bien apres l'affichage de la fenetre.

Je reste perplexe et... perdu.
Mais la vie est belle, si vs avez des questions, des suggestions, ou meme
qui sait, des reponses (djil ???), je suis pas tres loin.

Au plaisir,
Gil
Commenter la réponse de gilimcce
Messages postés
3011
Date d'inscription
jeudi 26 septembre 2002
Dernière intervention
27 novembre 2004
- 16 sept. 2004 à 22:57
0
Merci
jockos a repondu a ta question, mais si tu fais du c evite le cast du malloc qui est inutile
Commenter la réponse de cs_djl

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.