# Afficher les données d'un buffer



## tommyaltaïr (5 Mars 2008)

Bonjour, voilà j'ai écris du code sous xcode pour faire une acquisition d'une image d'un frame grabber pci que j'ai développé. Mon code sous cocoa me renvois un pointeur sur les données (12000 * 20000 gray 16 bits pixels). Je peux modifier les données dans le buffer pour passer en 8 bits(lookup). Je souhaite afficher cette image en utilisant la class NSBitmapImageRep. J'ai regarder les infos, mais en soit je cherche de l'aide pour caractériser mon buffer en une image en donnant le pointeur sur les data, la taille des lignes, le nombre de ligne, la structure des données... J'ai défini une fenêtre graphique avec interface buider (NSView), Je dessine des cercles, des carrés, ça marche. Quelqu'un peut il me donner des infos pour afficher mon buffer ? Merci


----------



## Didier Guillion (6 Mars 2008)

Désolé, je n'utilise ni Cocoa, ni Obj-C, mais peut etre du devrait voir du coté de 
NSCustomImageRep

Je laisse aux initiés le soin d'infimer, confirmer, completer.

Cordialement


----------



## Mala (6 Mars 2008)

Il te faut créer une instance de NSImage, ensuite tu vas créer une simple NSBitmapImageRep que tu lui associe. Tu récupères un pointeur sur ta représentation bitmap avec la méthode bitmapData. Tu as ainsi accès à ton "tableau de pixels".

Tu itères sur ton buffer pour en extraire les valeurs et les transférer vers ta représentation (ne pas oublier d'incrémenter aussi le pointeur de ta réprésentation. Ce serait dommage de tout mettre dans le même pixel... :rateau: ).

Pour finir, il ne te restera qu'a envoyer le contenu de l'image dans une NSImageView pour afficher le résultat.

Tu peux trouver un exemple concret ici...
http://macdevcenter.com/pub/a/mac/2002/08/06/cocoa.html


```
- (NSImage *)filterImage:(NSImage *)srcImage
{
    NSBitmapImageRep *srcImageRep = [NSBitmapImageRep
                    imageRepWithData:[srcImage TIFFRepresentation]];
    NSImage *destImage = [[NSImage alloc] initWithSize:NSMakeSize(w,h)];

    int w = [srcImageRep pixelsWide];
    int h = [srcImageRep pixelsHigh];
    int x, y;
       
    NSBitmapImageRep *destImageRep = [[[NSBitmapImageRep alloc] 
                    initWithBitmapDataPlanes:NULL
                    pixelsWide:w 
                    pixelsHigh:h 
                    bitsPerSample:8 
                    samplesPerPixel:1
                    hasAlpha:NO
                    isPlanar:NO
                    colorSpaceName:NSCalibratedWhiteColorSpace
                    bytesPerRow:NULL 
                    bitsPerPixel:NULL] autorelease];

    unsigned char *srcData = [srcImageRep bitmapData];
    unsigned char *destData = [destImageRep bitmapData];
    unsigned char *p1, *p2;

    for ( y = 0; y < h; y++ ) {
        for ( x = 0; x < w; x++ ) {
            
        }
    }
    
    [destImage addRepresentation:destImageRep];
    return destImage;
}
```

NB: comme tes informations son linéaires (pas d'entrelacement R,V,B) le mieux c'est de faire un memcpy des lignes.


----------



## tommyaltaïr (15 Mars 2008)

Bonjour Mala, ton code  m'a permis d'afficher une image. 
Je dis "une image car elle n'est pas la représentation de ce que je pensais voir :
La structure de mon buffer de pixel est organisé comme cela dans un premier temps : 
16 bit/pixel mais 10 bit actif. Si les bits sont tous à 1 et si je fais un dump dans Xcode, je lis 0x03ff pour le premier word.

Si la variable int bitsPerSample = 16 pour mon NSBitmapImageRep alors l'image est noir;
Si la variable int bitsPerSample = 12 pour mon NSBitmapImageRep alors l'image est noir aussi;

Si je change la variable colorSpaceName:NSCalibratedWhiteColorSpace par colorSpaceName:NSCalibratedblackColorSpace j'obtiens une images toutes blanches.

La question de je me pose est comment, partant de la taille d'un pixel de 16 bits le système affiche l'image. Le système tronque t'il les bits de poids faible, utilise t'il une lookup table ?
Merci


----------



## Mala (15 Mars 2008)

tommyaltaïr a dit:


> 16 bit/pixel mais 10 bit actif. Si les bits sont tous à 1 et si je fais un dump dans Xcode, je lis 0x03ff pour le premier word.


Oui c'est logique.



tommyaltaïr a dit:


> La question de je me pose est comment, partant de la taille d'un pixel de 16 bits le système affiche l'image. Le système tronque t'il les bits de poids faible, utilise t'il une lookup table ?
> Merci


Si tu travailles sur une image en 16bits OS X n'affiche que les bits de poids fort.

Si c'est juste pour visualiser, il te suffit d'utiliser le code que je t'ai donné mais en faisant un décalage de deux bits à droite (genre "destData = srcData>>2;". Tu auras alors une image visualisant les 8 bits de poids fort.

Si tu as besoin de sauvegarder tes 12 bits il te faut alors utiliser une représentation initialisée en 16bits (il ne me semble pas que 12bits soit supporté. C'est 8, 16, etc). Dans ce cas, tu fais un décalage de 6 bits vers la gauche et le tour est joué. Tu auras ainsi une image 16bits parfaitement visualisée sans perte d'information.


----------



## Mala (15 Mars 2008)

tommyaltaïr a dit:


> Si la variable int bitsPerSample = 16 pour mon NSBitmapImageRep alors l'image est noir;
> Si la variable int bitsPerSample = 12 pour mon NSBitmapImageRep alors l'image est noir aussi;


En toute logique avec un bitsPerSample à 16, ton image ne dois pas être parfaitement noir. Je dirais un léger gris à 3 sur 256 niveau.

Pour les 12bits, vérifies le pointeur de ta représentation mais je ne serais pas étonné qu'il soit à nil faute d'avoir réussi à s'initialiser.


----------



## tommyaltaïr (27 Mars 2008)

Slt, cela fait plusieurs jours que je me casse la tête avec le code qui suit. L'image obtenue est initialisée que sur sa moitié (les 8 premières lignes), mais pire encore,  mes pixels ne correspondent pas à la valeur que j'écris (123 à la place de 140). Par conte mon image est bonne si destData[x] = 255;

Voilà le code :

	int width = 16;
	int height = 16;
	int bpp = 8; 
	int x;
	unsigned char *destData;
	NSBitmapImageRep* MyImageRep

	MyImageRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
                pixelsWide:width 
				pixelsHigh:height
                bitsPerSample:bpp
				samplesPerPixel:1 
                hasAlpha:NO
				isPlanar:NO
                colorSpaceName:NSCalibratedWhiteColorSpace
                bytesPerRow:0
                bitsPerPixel:bpp];


	destData = [MyImageRep bitmapData];	

	for ( x = 0; x < width * height; y++ )
								{
								destData[x] = 140;
								}


	NSImage* imageFromBundle = [[NSImage alloc] init];
	[imageFromBundle addRepresentation: MyImageRep];
	[imageFromBundle autorelease];


	// save file
	NSArray *representations;
	NSData *bitmapData;

	representations = [imageFromBundle representations];

	bitmapData = [NSBitmapImageRep representationOfImageRepsInArray:representations 
    usingType: NSBMPFileType properties:nil];

	[bitmapData writeToFile"AnaAlta.bmp" atomically:YES];
	// save file


----------



## Mala (28 Mars 2008)

tommyaltaïr a dit:


> for ( x = 0; x < width * height; y++ )
> {
> destData[x] = 140;
> }


y++ ??? Je vais mettre ça sur le compte d'une faute de frappe.

A première vue, tu fais déjà une grosse erreur par rapport à l'exemple que je t'ai donné: Tu considères que toute ta matrice est sur une seule ligne continue.

De mémoire, en mettant le bytesPerRow à 0, tu laisses la classe gérer comme elle le souhaite la largeur du buffer. Regardes ce que te retourne la méthode bytesPerRow juste après ton init. Si tu ne veux pas avoir de surprise, initialises correctement la valeur de bytesPerRow de ta NSBitmapImageRep (soit à "width" dans ton cas puisque tu n'as qu'un octet par pixel).

Pour le reste, tu contrôles comment ton buffer pour obtenir 123 à la place de 140? Tu fais un NSLog dans la boucle?

PS: Evites le mutlti-postes sur différents sites, ça agace. 

PS2: je suppose que c'est juste un exemple extrait de ton code mais n'oublies pas le release sur MyImageRep ou alors passes l'instance en autorelease dès sa création sans quoi tu vas avoir des fuites. Et avec les images ça peut aller très vite...


----------



## tommyaltaïr (28 Mars 2008)

Salut Mala, excuse moi pour les multipost, je suis nouveau sur les forums et je trouve cette communauté fascinante...
Pour résoudre mon problème de valeur de pixel et de remplissage d'image j'ai changer mon image en RVB comme suit :

int x,y;
	int h,w;
	int bpr;
	int spp = 3;
	int adr;
	int bytesPerPixel;
	unsigned char *destData;	
	NSBitmapImageRep* MyImageRep;



	MyImageRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
				pixelsWide:width 
				pixelsHigh:height
                                bitsPerSample:bpp
				samplesPerPixel:spp
                                hasAlpha:NO
				isPlanar:NO
                                colorSpaceName:NSCalibratedRGBColorSpace
				bytesPerRow:0
                                bitsPerPixel:bpp * spp];


	destData = [MyImageRep bitmapData];
	bpr = [MyImageRep bytesPerRow];

        for (y = 0; y < height; y++)
              for ( x = 0; x < width; x++ )
                    {
		       adr = y * bpr + x * spp;
                       destData[adr] = 140;
                       destData[adr + 1] = 140;
                       destData[adr + 2] = 140;   
                     }


	NSImage* imageFromBundle = [[NSImage alloc] init];
	[imageFromBundle addRepresentation: MyImageRep];
	[imageFromBundle autorelease];



// save file
NSArray *representations;
NSData *bitmapData;

representations = [imageFromBundle representations];

bitmapData = [NSBitmapImageRep representationOfImageRepsInArray:representations 
    usingType: NSBMPFileType properties:nil];

[bitmapData writeToFile"AnaAlta.bmp" atomically:YES];
// save file


Par contre si 
	int spp = 1; et colorSpaceName:NSCalibratedWhiteColorSpace

       for (y = 0; y < height; y++)
              for ( x = 0; x < width; x++ )
                    {
		       adr = y * bpr + x * spp;
                       destData[adr] = 140;      
                     }
les images lue dans photoshop me donne une valeur de pixel à 123
J'ai édité l'image avec un hexeditor et la valeur 123 est confirmée.


----------



## Mala (29 Mars 2008)

J'ai remis ton code en forme pour avoir un test qui compile.


```
-(void)test
{
    int x,y; 
    int height=100,width=100;
    int bpp = 8;
    int spp = 1;
    int adr;
    int bpr=0;
    unsigned char *destData;	
    NSBitmapImageRep* myImageRep;
    
    
    
    myImageRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                          pixelsWide:width 
                                                          pixelsHigh:height
                                                       bitsPerSample:bpp
                                                     samplesPerPixel:spp
                                                            hasAlpha:NO
                                                            isPlanar:NO
                                                      colorSpaceName:NSCalibratedWhiteColorSpace//NSCalibratedRGBColorSpace
                                                         bytesPerRow:bpp*spp*width/8
                                                        bitsPerPixel:bpp*spp] autorelease];
    
    
    destData = [myImageRep bitmapData];
    bpr      = [myImageRep bytesPerRow];
    
    for (y = 0; y < height; y++)
    {
        for ( x = 0; x < width; x++ )
        {
            adr = y * bpr + x * spp;
            destData[adr] = 140;
            
            // destData[adr + 1] = 140;
            // destData[adr + 2] = 140;
        }
    }
    
    NSImage* imageFromBundle = [[[NSImage alloc] init] autorelease];
    [imageFromBundle addRepresentation:myImageRep];
    
    // save file
    NSArray *representations;
    NSData *bitmapData;
    
    representations = [imageFromBundle representations];
    
    bitmapData = [NSBitmapImageRep representationOfImageRepsInArray:representations 
                                                          usingType:NSBMPFileType 
                                                         properties:nil];
    
    [bitmapData writeToFile:@"AnaAlta.bmp" atomically:YES];
}
```

Avec la pipette sous aperçu, j'ai bien une image BMP où chaque pixel vaut 140. Anecdote amusante au passage, la sauvegarde BMP repasse l'image en RVB.


----------



## tommyaltaïr (31 Mars 2008)

J'ai trouvé.C'est étrange mais si je change le profile de couleur de mon moniteur, cela change aussi les données de mon image. Mon moniteur est un Apple Cinema Display 30" et je suis passé d'un profile étalonné au profile de base Cinema HD Display. Merci pour l'aide


----------



## Mala (1 Avril 2008)

Donc pour terminer le sujet. Comme souligné par AliGator sur le macfr.com (Post "image niveau de gris") NS*Calibrated*WhiteColorSpace doit être remplacé par NS*Device*WhiteColorSpace sinon effectivement l'information est altérée si on utilise une calibration d'écran maison. Hors c'est bien sûr à proscrire ici.


----------



## tommyaltaïr (8 Avril 2008)

Le changement de NSCalibratedWhiteColorSpace en NSDeviceWhiteColorSpace ne donne pas d'amélioration.

NSDeviceWhiteColorSpace
Device-dependent color space with white and alpha components (pure white is 1.0)


----------

