1
votes

I am doing some image manipulation which creates an image on a transparent background. I'm working with OpenCV (C++) and iOS. To begin, I setup a 4 channel 8 bit matrix, set all pixels to white with alpha 0 (is this correct?). Then copy the pixels from result into foreground:

 cv::Mat foreground(image.size(),CV_8UC4, cv::Scalar(255,255,255,0));
 image.copyTo(foreground, result);

Next, I need to convert this Mat into a UIImage, the code I was using for this:

+(UIImage *)UIImageFromCVMat:(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);

    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(cvMat.cols,                                 //width
                                        cvMat.rows,                                 //height
                                        8,                                          //bits per component
                                        8 * cvMat.elemSize(),                       //bits per pixel
                                        cvMat.step[0],                            //bytesPerRow
                                        colorSpace,                                 //colorspace
                                        kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
                                        provider,                                   //CGDataProviderRef
                                        NULL,                                       //decode
                                        false,                                      //should interpolate
                                        kCGRenderingIntentDefault                   //intent
                                        );

    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    return finalImage;
}

This works fine for generating my image, but I noticed it wasn't transparent. So I figured instead using CGImageCreate, I could use:

CGImageRef imageRef = CGImageCreateWithPNGDataProvider(provider, NULL, false, kCGRenderingIntentDefault);

However I'm not sure if CGImageCreateWithPNGDataProvider is the right call, I'm not sure if the provider is formatted correctly for this method.

I have also checked to make sure my imageView.opaque = NO;.

Does anyone know the easiest way to convert a cv::Mat to PNG with transparency? Thanks

*EDIT: I also tried tinkering with some of the flags for bitmap info on the original CGImageCreate function:

kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */
  kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
  kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */
  kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */
  kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */
  kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */

However, I get an error of <Error>: CGImageCreate: invalid image bits/pixel: 24. which I'm not sure how to interpret, since I initialized the cv::Mat foreground with 4 channels.

1

1 Answers

1
votes

It looks like the problem is copyTo method. From the doc:

The method copies the matrix data to another matrix. Before copying the data, the method invokes

m.create(this->size(), this->type());

It looks like it overrides your setup of foreground. You need to find another way to copy bits to get alpha channel.