Afficher les données d'un buffer

tommyaltaïr

Membre confirmé
5 Mars 2008
25
0
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
 
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

Bloc de code:
- (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.
 
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
 
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.

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.
 
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.
 
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
 
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...
 
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.
 
J'ai remis ton code en forme pour avoir un test qui compile.

Bloc de code:
-(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.
 
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
 
Donc pour terminer le sujet. Comme souligné par AliGator sur le macfr.com (Post "image niveau de gris") NSCalibratedWhiteColorSpace doit être remplacé par NSDeviceWhiteColorSpace sinon effectivement l'information est altérée si on utilise une calibration d'écran maison. Hors c'est bien sûr à proscrire ici.
 
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)