2011-11-15 2 views
14

Questo codice funziona principalmente, ma i dati risultanti sembrano perdere un canale di colore (è quello che sto pensando) poiché i dati dell'immagine risultanti quando sono visualizzati sono colorati di blu!Converti UIImage in CVImageBufferRef

Ecco il codice:

UIImage* myImage=[UIImage imageNamed:@"sample1.png"]; 
CGImageRef imageRef=[myImage CGImage]; 
CVImageBufferRef pixelBuffer = [self pixelBufferFromCGImage:imageRef]; 

Il metodo pixelBufferFromCGIImage è stato afferrato da un altro post su StackOverflow qui: How do I export UIImage array as a movie? (anche se questa applicazione non è correlato a quello che sto cercando di fare) è

+ (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image 
{ 
    CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); 
    NSDictionary *options = @{ 
           (__bridge NSString *)kCVPixelBufferCGImageCompatibilityKey: @(NO), 
           (__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(NO) 
           }; 
    CVPixelBufferRef pixelBuffer; 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, 
              frameSize.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, 
              &pixelBuffer); 
    if (status != kCVReturnSuccess) { 
     return NULL; 
    } 

    CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
    void *data = CVPixelBufferGetBaseAddress(pixelBuffer); 
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height, 
               8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, 
               (CGBitmapInfo) kCGImageAlphaNoneSkipLast); 
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
              CGImageGetHeight(image)), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 

    return pixelBuffer; 
} 

Sto pensando che abbia qualcosa a che fare con la relazione tra kCVPixelFormatType_32ARGB e kCGImageAlphaNoneSkipLast sebbene abbia provato ogni combinazione e abbia ottenuto lo stesso risultato o un crash dell'applicazione. Ancora una volta, questo ottiene i dati UIImage in CVImageBufferRef ma quando visualizzo l'immagine sullo schermo, sembra perdere un canale di colore e si presenta colorato di blu. L'immagine è un png.

risposta

-1

Sembra che potrebbe essere quel rapporto. Forse dovrebbe essere un jpg e RGB invece di colori indicizzati con una PNG?

+2

Grazie per la risposta. La soluzione è che questo codice funziona perfettamente come previsto. Il problema era nell'usare i dati nella creazione di una trama OpenGL. Completamente estraneo a questo codice. Chiunque cerchi come convertire UIImage in CVImageBufferRef, la tua risposta è nel codice sopra! – Eric

+0

Per riferimento: PNG non è necessariamente indicizzato (come GIF), supporta anche immagini RGB a colori senza perdita (ovviamente funziona meglio con disegni a linee e blocchi a tinta unita) – Ethan

5

La soluzione è che questo codice funziona perfettamente come previsto. :) Il problema era nell'usare i dati nella creazione di una trama OpenGL. Completamente estraneo a questo codice. Chiunque cerchi come convertire UIImage in CVImageBufferRef, la tua risposta è nel codice sopra!

+0

No, sicuramente non funziona.Devi usare 'kCVPixelFormatType_32BGRA' e usare' (CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst' come ultima variabile per 'context'. Inoltre, le "opzioni NSDictionary" sono inutili. IMO –

0

solo per chiarire la risposta di cui sopra: Ho incontrato lo stesso problema perché il mio codice degli shader aspettava due campioni stratificati all'interno di un buffer di immagine, mentre io ho usato un buffer singolo strato

Questa linea ha preso i valori RGB da un campione e passato a (non so cosa), ma il risultato finale è un'immagine a colori.

gl_FragColor = vec4(texture2D(SamplerY, texCoordVarying).rgb, 1); 
1

Se qualcuno è ancora alla ricerca di una soluzione a questo problema, ho risolto cambiando le BOOL nelle opzioni del pixelBuffer:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
        [NSNumber numberWithBool:NO], kCVPixelBufferCGImageCompatibilityKey, 
        [NSNumber numberWithBool:NO], kCVPixelBufferCGBitmapContextCompatibilityKey, 
        nil]; 

da No a Sì:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
        [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
        [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, 
        nil]; 
1

Incontro lo stesso problema e trovo dei campioni: http://www.cakesolutions.net/teamblogs/2014/03/08/cmsamplebufferref-from-cgimageref
prova a cambiare

CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGBitmapByteOrder32Little | 
        kCGImageAlphaPremultipliedFirst) 
+0

Per me ha funzionato! solo così le persone possono vedere la parte del codice, CGContextRef context = cambia il valore passato da quello da kCGImageAlphaNoneSkipLast a kCGImageAlphaPremultipliedFirst. – Charlie

1

Ecco cosa funziona davvero:

+ (CVPixelBufferRef)pixelBufferFromImage:(CGImageRef)image { 
    CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); // Not sure why this is even necessary, using CGImageGetWidth/Height in status/context seems to work fine too 

    CVPixelBufferRef pixelBuffer = NULL; 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, frameSize.height, kCVPixelFormatType_32BGRA, nil, &pixelBuffer); 
    if (status != kCVReturnSuccess) { 
     return NULL; 
    } 

    CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
    void *data = CVPixelBufferGetBaseAddress(pixelBuffer); 
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height, 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, (CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); 

    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 

    return pixelBuffer; 
} 

È possibile modificare il buffer dei pixel di nuovo ad un UIImage (e quindi visualizzare o salvarlo) per confermare che funziona con questo metodo:

+ (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBuffer { 
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; 
    CIContext *context = [CIContext contextWithOptions:nil]; 
    CGImageRef myImage = [context createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))]; 
    UIImage *image = [UIImage imageWithCGImage:myImage]; 

    // Uncomment the following lines to say the image to your application's document directory 
    //NSString *imageSavePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"myImageFromPixelBuffer.png"]]; 
    //[UIImagePNGRepresentation(image) writeToFile:imageSavePath atomically:YES]; 
    return image; 
}