how to convert from cvMat to UIImage in objective-c? how to convert from cvMat to UIImage in objective-c? xcode xcode

how to convert from cvMat to UIImage in objective-c?


Note: most implementations don't correctly handle an alpha channel or convert from OpenCV's BGR pixel format to iOS's RGB.

This will correctly convert from cv::Mat to UIImage:

+(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat {    NSData *data = [NSData dataWithBytes:cvMat.data length:image.step.p[0]*image.rows];    CGColorSpaceRef colorSpace;    CGBitmapInfo bitmapInfo;    if (cvMat.elemSize() == 1) {        colorSpace = CGColorSpaceCreateDeviceGray();        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;    } else {        colorSpace = CGColorSpaceCreateDeviceRGB();        bitmapInfo = kCGBitmapByteOrder32Little | (            cvMat.elemSize() == 3? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst        );    }    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        bitmapInfo,                 // 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; }

And to convert from UIImage to cv::Mat:

+ (cv::Mat)cvMatWithImage:(UIImage *)image{    CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);    size_t numberOfComponents = CGColorSpaceGetNumberOfComponents(colorSpace);    CGFloat cols = image.size.width;    CGFloat rows = image.size.height;    cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels    CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault;    // check whether the UIImage is greyscale already    if (numberOfComponents == 1){        cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channels        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;    }     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                                                bitmapInfo);              // Bitmap info flags    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);    CGContextRelease(contextRef);    return cvMat;}


From opencv 2.4.6 on this functionality is already included.Just include

opencv2/highgui/ios.h

In OpenCV 3 this include has changed to:

opencv2/imgcodecs/ios.h

And you can use these functions:

UIImage* MatToUIImage(const cv::Mat& image);void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist = false);


Here is the correct method to convert a cv::Mat to a UIImage.

Every other implementation I've seen — including OpenCV's documentation — is incorrect: they do not correctly convert from OpenCV's BGR to iOS's RGB, and they do not consider the alpha channel (if one exists). See comments above bitmapInfo = ….

+(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat {    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];    CGColorSpaceRef colorSpace;    CGBitmapInfo bitmapInfo;    if (cvMat.elemSize() == 1) {        colorSpace = CGColorSpaceCreateDeviceGray();        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;    } else {        colorSpace = CGColorSpaceCreateDeviceRGB();        // OpenCV defaults to either BGR or ABGR. In CoreGraphics land,        // this means using the "32Little" byte order, and potentially        // skipping the first pixel. These may need to be adjusted if the        // input matrix uses a different pixel format.        bitmapInfo = kCGBitmapByteOrder32Little | (            cvMat.elemSize() == 3? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst        );    }    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        bitmapInfo,                 // 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; }