[OpenCV]关于图片通道转换的相关问题

2016-11-30  本文已影响1843人  油焖微风

月初在研究OpenCV时发现一个问题就是很难解决,在stackoverflow上都很难找到解决的方案,问题是在调用 OpenCV的修复函数 inpaint(img, inpaintMask, inpainted, 3, INPAINT_TELEA); 报错,提示语为:“ OpenCV Error: Unsupported format or combination of formats (Only 8-bit 1-channel and 3-channel input/output images are supported) in cvInpaint, ” 错误原因为输入的inpaintMask代表的图像格式有问题,其通道数和位数不符合要求。

一、背景知识

RGB色彩模式 RGB色彩模式指的是红、绿、蓝(Red、Green、Blue)三个通道的颜色,而一般png图片是带有Alpha通道的(也就是俗称的透明度),也就是第四个通道。而单通道色彩模式实际上就是我们熟知的黑白图片。错误提示语中的“8-bit 1-channel”指的就是用8个bit(即1个字节)来表示单通道色阶的图片。而“8-bit 3-channel” 指的就是只有RGB三个通道的图片,没有Alpha通道,每个通道用8bit表示。

二、解决方案

也解决这个问题涉及到一个通道转到换和位数转换的问题。下面将分步介绍这个转换,这里我们采用OpenCV的iOS版本来阐述,只是开始获取图像数据时用到了Objective-C语言,其他时候都是调用C++/C语言,其转换部分是具有通用性的。

Mat img0 = [[UIImage imageNamed:@"apple01"] cvMatRepresentationColor];//获取图像数据,用Mat类来表示

第一步将其转换为结构体IplImage (IplImage , Mat 和CvMat 之间是可以相互转换的,都是代表图像数据的结构体或者类),根据其尺寸用cvCreateImage()创建能够存储3通道的图片结构体的内存区域,并用指针变量img3chan指向它

IplImage img = img0;//可以直接赋值转换为结构体
IplImage *img3chan = cvCreateImage(cvGetSize(&img),img.depth, 3);

第二步是用cvCvtColor方法将img中的原始图片数据转化为RGB三通道的图片,并将图片数据保存到img3chan中。

cvCvtColor(&img,img3chan,CV_RGBA2RGB);//CV_RGBA2RGB表示4通道转成3通道

第三步是要完成位数的转换,以上几步只是完成通道数量的转换,同样我们需要用一个方法cvCreateMat()创建一个新的内存区域来作为容器来存放转换后的结果,最后用cvConvert()完成最终转换

    CvMat *cvMat = cvCreateMat(img.height, img.width, CV_8UC3);//创建容器区域
    cvConvert(img3chan, cvMat);

以下是完整代码:

- (void)handleInpaint{
    Mat img0 = [[UIImage imageNamed:@"apple01"] cvMatRepresentationColor];//
    IplImage img = img0;
    IplImage *img3chan = cvCreateImage(cvGetSize(&img),img.depth, 3);
    cvCvtColor(&img,img3chan,CV_RGBA2RGB);
    CvMat *cvMat = cvCreateMat(img.height, img.width, CV_8UC3);
    cvConvert(img3chan, cvMat);
    Mat img2 = Mat(cvMat);
    Mat inpaintMask = Mat::zeros(img2.size(), CV_8U);
    
    Vector<Mat> res = inpaintImage(img0,inpaintMask);
    if(res.size() >= 2){
        self.imgV.image = [UIImage imageFromCVMat:res[0]];
        self.imgV0.image = [UIImage imageFromCVMat:res[1]];
    }
}

Vector<Mat> inpaintImage(Mat&img0,Mat&inpaintMask){
    Vector<Mat>res_imgs;
    if(img0.empty()){
        return res_imgs;
    }
    Mat img = img0.clone();
    Mat inpainted;
    inpaint(img, inpaintMask, inpainted, 3, INPAINT_TELEA);
    res_imgs.push_back(inpainted);
    res_imgs.push_back(inpaintMask);
//    imshow("修复后", inpainted);
//    imshow("图像掩码",inpaintMask);
    return res_imgs;
}
上一篇下一篇

猜你喜欢

热点阅读