2013-06-06 19 views
5

Sono, lo sviluppo di un'applicazione iOS che utilizza alcune funzionalità OpenCV (rimuovere lo sfondo, i rilevamenti dei bordi ecc)OpenCV ios un'immagine trasparente caricata senza trasparenza

Tra le altre cose, mi carico immagini trasparenti (PNG). Per qualche motivo, quando carico le immagini, opencv decide di ignorare alcune aree trasparenti nel rispetto degli altri. Posso vedere questo convertendo il mio UIImage semi trasparente in un IplImage e poi di nuovo in UIImage (senza fare alcuna operazione sull'iplimage) e salvando entrambe le immagini nel file locale.

Questo è il codice che sto utilizzando per la conversione l'UIImage a un IplImage e indietro:

- (IplImage *)CreateIplImageFromUIImageWithTransparency:(UIImage *)image { 
    // Getting CGImage from UIImage 
    CGImageRef imageRef = image.CGImage; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    // Creating temporal IplImage for drawing 
    IplImage *iplimage = cvCreateImage(
             cvSize(image.size.width,image.size.height), IPL_DEPTH_8U, 4 
             ); 
    // Creating CGContext for temporal IplImage 
    CGContextRef contextRef = CGBitmapContextCreate(
                iplimage->imageData, iplimage->width, iplimage->height, 
                iplimage->depth, iplimage->widthStep, 
                colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault 
                ); 
    // Drawing CGImage to CGContext 
    CGContextDrawImage(
         contextRef, 
         CGRectMake(0, 0, image.size.width, image.size.height), 
         imageRef 
         ); 
    CGContextRelease(contextRef); 
    CGColorSpaceRelease(colorSpace); 

    // Creating result IplImage 
    IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, 4); 
    cvCvtColor(iplimage, ret, CV_RGBA2BGRA); 
    cvReleaseImage(&iplimage); 

    return ret; 
} 


- (UIImage *)UIImageFromIplImage:(IplImage *)image { 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    NSData *data = [NSData dataWithBytes:image->imageData length:image->imageSize]; 
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 
    CGImageRef imageRef = CGImageCreate(image->width, image->height, 
             image->depth, image->depth * image->nChannels, image->widthStep, 
             colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast , 
             provider, NULL, false, kCGRenderingIntentDefault); 
    UIImage *ret = [UIImage imageWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    CGDataProviderRelease(provider); 
    CGColorSpaceRelease(colorSpace); 
    return ret; 
} 

cosa potrebbe causare questo comportamento?

Grazie

risposta

1
IplImage *ret = cvLoadImage("file.png", CV_LOAD_IMAGE_UNCHANGED); 

dare un'occhiata a doc: http://opencv.willowgarage.com/documentation/c/reading_and_writing_images_and_video.html

CV_LOAD_IMAGE_UNCHANGED l'immagine caricata verrà caricato come è mentre l'argomento di default convertire l'img in RGB

+0

Non posso, questo non è un file salvato sulla directory locale. Piuttosto è salvato nella memoria del programma. Salvare l'immagine in un file e caricarla di nuovo sarà molto inefficiente (e io ho bisogno di un certo livello di efficienza in questo metodo). – vondip

+0

Hum ... Mi dispiace, non ho prestato attenzione, forse dovresti dare un'occhiata a questo: http://stackoverflow.com/questions/6861891/how-do-you-generate-an-rgba-image -in-core-graphics – Poko

+0

Sì, se si nota nel mio CreateIplImageFromUIImageWithTransparency, chiamo kCGImageAlphaPremultipliedLast come consigliato in questa domanda – vondip

2

Penso che questo è dove il problema è:

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

Non dovresti usare RGBA qui?

+0

beh, non c'è supporto CGColorSpaceCreateDeviceRGBA :(solo CGColorSpaceCreateDeviceRGB – vondip

+1

Spiacente, dovrei averlo controllato prima. Ho controllato i miei progetti precedenti e scoperto che ho utilizzato kCGImageAlphaNone in loro CGBitmapContextCreate con kCGImageAlphaPremultipliedLast si suppone che ha creato il contesto corretto solo un paio di domande da quando anche io voglio trovare una soluzione:.. 1. Se s alcune delle aree trasparenti sono ignorate, potrebbe accadere perché l'ordine dei canali in qualche modo va storto? 2. Perché kCGImageAlphaLast è utilizzato in CGImageCreate()? – Totoro

+0

beh, in realtà non sono sicuro al 100%, anche se so che se uso kCGImageAlphaPremultipliedLast invece di kCGImageAlphaLast ottengo il seguente errore: : CGBitmapContextCreate: combinazione di parametri non supportati: 8 bit interi/componente; 32 bit/pixel; Spazio colore a 3 componenti; kCGImageAlphaLast; 2200 byte/riga. – vondip

4

Questo codice funziona per me. Ho modificato il codice here

lettura da UIImage

-(cv::Mat)CVMat 
{ 

    CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage); 
    CGFloat cols = self.size.width; 
    CGFloat rows = self.size.height; 

    cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels 

    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,     // Pointer to backing data 
                cols,      // Width of bitmap 
                rows,      // Height of bitmap 
                8,       // Bits per component 
                cvMat.step[0],    // Bytes per row 
                colorSpace,     // Colorspace 
                //kCGImageAlphaNoneSkipLast | 
                kCGImageAlphaPremultipliedLast | 
                kCGBitmapByteOrderDefault); // Bitmap info flags 

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage); 
    CGContextRelease(contextRef); 

    return cvMat; 
} 

La riconversione UIImage:

+ (UIImage *)imageWithCVMat:(const cv::Mat&)cvMat 
{ 
    return [[UIImage alloc] initWithCVMat:cvMat]; 
} 

- (id)initWithCVMat:(const cv::Mat&)cvMat 
{ 
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; 

    CGColorSpaceRef colorSpace; 

    if (cvMat.elemSize() == 1) 
    { 
     colorSpace = CGColorSpaceCreateDeviceGray(); 
    } 
    else 
    { 
     colorSpace = CGColorSpaceCreateDeviceRGB(); 
    } 

    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 

    CGImageRef imageRef = CGImageCreate(cvMat.cols,          // Width 
             cvMat.rows,          // Height 
             8,            // Bits per component 
             8 * cvMat.elemSize(),       // Bits per pixel 
             cvMat.step[0],         // Bytes per row 
             colorSpace,          // Colorspace 
             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault, // Bitmap info flags 
             provider,          // CGDataProviderRef 
             NULL,           // Decode 
             false,           // Should interpolate 
             kCGRenderingIntentDefault);      // Intent 

    self = [self initWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    CGDataProviderRelease(provider); 
    CGColorSpaceRelease(colorSpace); 

    return self; 
}