如何在objective-c中从cvMat转换为UIImage?

cho*_*vil 28 xcode opencv objective-c

我正在使用OpenCV框架与XCode,并希望从cvMat或IplImage转换为UIImage,该怎么做?谢谢.

sch*_*sch 44

注意:大多数实现都无法正确处理Alpha通道或从OpenCV的BGR像素格​​式转换为iOS的RGB.

这将正确转换cv::MatUIImage:

+(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; 
}
Run Code Online (Sandbox Code Playgroud)

并转换UIImagecv::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;
}
Run Code Online (Sandbox Code Playgroud)

  • 当从cv :: Mat转换为UIImage时,我不得不交换红色和蓝色通道.似乎opencv中的默认顺序是bgr.这是你需要的代码行:cvtColor(image,image,CV_BGR2RGB); (16认同)
  • 我正在尝试同样的事情,我已经尝试了 @huesforalice 在他的评论中所说的事情,但它正在改变图像的完整色彩空间。然后我尝试了另一个补丁,首先从 BGR2RGB 转换,然后再次转换回 RGB2BGR,然后将其传递以转换回 UIImage,令人惊讶的是它有效...在调用 UIImageFromCVMat, `cvtColor(cvMat, cvMat, CV_BGR2RGB) 之前添加这 2 行; cvtColor(cvMat, cvMat, CV_RGB2BGR);` (2认同)

AxM*_*AxM 31

从opencv 2.4.6开始,此功能已包含在内.只是包括

opencv2/highgui/ios.h

在OpenCV 3中,此包含已更改为:

opencv2/imgcodecs/ios.h

你可以使用这些功能:

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

  • 不幸的是,“MatToUIImage”还受到已接受答案的评论中描述的红色和蓝色通道交换的影响。 (2认同)

Dav*_*ver 5

这是将a转换为a 的正确方法.cv::MatUIImage

我见过的所有其他实现 - 包括OpenCV的文档 - 都是错误的:它们没有正确地从OpenCV的BGR转换为iOS的RGB,并且它们不考虑alpha通道(如果存在).见上面的评论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; 
}
Run Code Online (Sandbox Code Playgroud)


cde*_*urs 5

您应该考虑使用本机OpenCV函数来回转换:

#import <opencv2/imgcodecs/ios.h>
...
UIImage* MatToUIImage(const cv::Mat& image);
void UIImageToMat(const UIImage* image,
                         cv::Mat& m, bool alphaExist = false);
Run Code Online (Sandbox Code Playgroud)