Fawkes
Fawkes

Reputation: 3941

iOS OpenCV cvtColor unknown array type error

I am starting with OpenCV on iOS and the first thing I wanted to achieve was transforming a colour image into a grey one.

My first attempt was successful

I was obtaining a Mat with "CV_8UC1" option and then converting it back to a image.

The code is as follows:

UIImage *image = [UIImage imageNamed:kImageName];

image = [UIImage greyedImage:image];

[imageView setImage:image];

+ (UIImage*)greyedImage:(UIImage*)image
{
    return [UIImage imageFromMat:[image toGrayMat]];
}


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

}

- (cv::Mat)toGrayMat
{
    cv::Mat tmp = [self toMatWithChannelOption:CV_8UC1];

    //cvCvtColor(&tmp, &tmp, CV_BGR2GRAY);

    return tmp;
}

- (cv::Mat)toMatWithChannelOption:(int)channelOption
{
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage);
    CGFloat cols = self.size.width;
    CGFloat rows = self.size.height;

    cv::Mat cvMat(rows, cols, channelOption); // 8 bits per component, 4 channels (color channels + alpha)

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

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

    return cvMat;

}

but it was causing this error

"CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaNoneSkipLast; 610 bytes/row. May 18 15:32:23 MacBook-Air.local test[12677] : CGContextDrawImage: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update."

After that I tried using cvtColor like this:

- (cv::Mat)toGrayMat
{
    cv::Mat tmp = [self toMatWithChannelOption:CV_8UC4];

    cvCvtColor(&tmp, &tmp, CV_BGRA2GRAY);

    return tmp;
}

But know I get

"Unknown array type in function cvarrToMat".. Somehow it tells me that the arguments passed to cvtColor are incorrect.

Please suggest what can be the reason.

p.s. I Observed in a lot of questions that other guys are calling the function as "cvtColor", while I am able to write it only as cvCvtColor, otherwise Xcode corrects it and also forces me to put the "&" before the mat function attributes.

My imports: "opencv2/imgproc/imgproc_c.h" iOS: 8+

Upvotes: 1

Views: 1977

Answers (1)

kiranpradeep
kiranpradeep

Reputation: 11201

Using cvCvtColor with CV_BGRA2GRAY as parameter converts a color image to a gray scale image. Each of those are Mat of different types. The color image has 4 channels ( e.g. CV_8UC4 ) and gray scale has a single channel ( e.g. CV_8UC1 ). So declare separate parameters for input and output. Sample below.

#include "opencv2/opencv.hpp"
cv::Mat gray;
cv::Mat tmp = [self toMatWithChannelOption:CV_8UC4];
cv::cvtColor( tmp, gray, CV_BGRA2GRAY );

Note a) Avoid using cvCvtColor as it is part of deprecated C API(1). Instead use cvtColor. b) Avoid using header imgproc_c.h. It is provided only for compatibility reasons. Instead use imgproc.hpp or simply opencv.hpp

Upvotes: 4

Related Questions