2010-01-03 14 views

risposta

9

suggerisco creare il proprio bitmap context, avvolgendolo in un graphics context e l'impostazione che il contesto attuale, telling the image to draw itself, e quindi l'accesso ai dati dei pixel dietro contesto bitmap direttamente.

Questo sarà più codice, ma consentirà di risparmiare sia un viaggio attraverso una rappresentazione TIFF che la creazione di migliaia o milioni di oggetti NSColor. Se stai lavorando con immagini di dimensioni apprezzabili, queste spese si sommano rapidamente.

6

Ottieni uno NSBitmapImageRep dal tuo NSImage. Quindi puoi accedere ai pixel.

NSImage* img = ...; 
NSBitmapImageRep* raw_img = [NSBitmapImageRep imageRepWithData:[img TIFFRepresentation]]; 
NSColor* color = [raw_img colorAtX:0 y:0]; 
+3

Questo è un approccio molto costoso, come 'colorAtX: y:' comporterà creando un'istanza 'NSColor' per ogni pixel, come Peter Note di Hosey. È molto più efficiente ottenere il buffer dei dati grezzi e utilizzare i puntatori per calcolare l'istogramma. – gavinb

+3

Ciao gavinb, hai qualche indicazione (prendi il buffer dei dati grezzi e cammina usando i puntatori) su questo? Grazie! – RickON

+0

@clearlight Beh, non mi ero reso conto che stavo tenendo qualcuno in sospeso. Ho scritto un'app di esempio che fa esattamente ciò che è descritto sopra e ho aggiunto il codice in una risposta a questa domanda. L'ho pubblicato anche su github. Godere! – gavinb

1

Cercare "istogramma" nella documentazione di Core Image.

2

Questo codice rende il NSImage in un CGBitmapContext:

- (void)updateImageData { 

    if (!_image) 
     return; 

    // Dimensions - source image determines context size 

    NSSize imageSize = _image.size; 
    NSRect imageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height); 

    // Create a context to hold the image data 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 

    CGContextRef ctx = CGBitmapContextCreate(NULL, 
              imageSize.width, 
              imageSize.height, 
              8, 
              0, 
              colorSpace, 
              kCGImageAlphaPremultipliedLast); 

    // Wrap graphics context 

    NSGraphicsContext* gctx = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:NO]; 

    // Make our bitmap context current and render the NSImage into it 

    [NSGraphicsContext setCurrentContext:gctx]; 
    [_image drawInRect:imageRect]; 

    // Calculate the histogram 

    [self computeHistogramFromBitmap:ctx]; 

    // Clean up 

    [NSGraphicsContext setCurrentContext:nil]; 
    CGContextRelease(ctx); 
    CGColorSpaceRelease(colorSpace); 
} 

Dato un contesto bitmap, si può accedere ai dati di immagine grezzi direttamente, e calcolare gli istogrammi per ciascun canale di colore:

- (void)computeHistogramFromBitmap:(CGContextRef)bitmap { 

    // NB: Assumes RGBA 8bpp 

    size_t width = CGBitmapContextGetWidth(bitmap); 
    size_t height = CGBitmapContextGetHeight(bitmap); 

    uint32_t* pixel = (uint32_t*)CGBitmapContextGetData(bitmap); 

    for (unsigned y = 0; y < height; y++) 
    { 
     for (unsigned x = 0; x < width; x++) 
     { 
      uint32_t rgba = *pixel; 

      // Extract colour components 
      uint8_t red = (rgba & 0x000000ff) >> 0; 
      uint8_t green = (rgba & 0x0000ff00) >> 8; 
      uint8_t blue = (rgba & 0x00ff0000) >> 16; 

      // Accumulate each colour 
      _histogram[kRedChannel][red]++; 
      _histogram[kGreenChannel][green]++; 
      _histogram[kBlueChannel][blue]++; 

      // Next pixel! 
      pixel++; 
     } 
    } 
} 

@end 

Ho pubblicato un progetto completo, un'app di esempio Cocoa, che include quanto sopra.

0

Utilizzando colorAtX con NSBitmapImageRep non sempre porta alla esatto colore corretto.

sono riuscito ad ottenere il colore corretto con questo semplice codice:

[yourImage lockFocus]; // yourImage is just your NSImage variable 
NSColor *pixelColor = NSReadPixel(NSMakePoint(1, 1)); // Or another point 
[yourImage unlockFocus];