月初在研究OpenCV時發(fā)現(xiàn)一個問題就是很難解決酸些,在stackoverflow上都很難找到解決的方案逾冬,問題是在調(diào)用 OpenCV的修復(fù)函數(shù) 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代表的圖像格式有問題景埃,其通道數(shù)和位數(shù)不符合要求。
一播掷、背景知識
RGB色彩模式 RGB色彩模式指的是紅咙边、綠猜煮、藍(lán)(Red、Green败许、Blue)三個通道的顏色王带,而一般png圖片是帶有Alpha通道的(也就是俗稱的透明度),也就是第四個通道市殷。而單通道色彩模式實際上就是我們熟知的黑白圖片愕撰。錯誤提示語中的“8-bit 1-channel”指的就是用8個bit(即1個字節(jié))來表示單通道色階的圖片。而“8-bit 3-channel” 指的就是只有RGB三個通道的圖片被丧,沒有Alpha通道盟戏,每個通道用8bit表示。
二甥桂、解決方案
也解決這個問題涉及到一個通道轉(zhuǎn)到換和位數(shù)轉(zhuǎn)換的問題柿究。下面將分步介紹這個轉(zhuǎn)換,這里我們采用OpenCV的iOS版本來闡述黄选,只是開始獲取圖像數(shù)據(jù)時用到了Objective-C語言蝇摸,其他時候都是調(diào)用C++/C語言婶肩,其轉(zhuǎn)換部分是具有通用性的。
Mat img0 = [[UIImage imageNamed:@"apple01"] cvMatRepresentationColor];//獲取圖像數(shù)據(jù)貌夕,用Mat類來表示
第一步將其轉(zhuǎn)換為結(jié)構(gòu)體IplImage (IplImage , Mat 和CvMat 之間是可以相互轉(zhuǎn)換的律歼,都是代表圖像數(shù)據(jù)的結(jié)構(gòu)體或者類),根據(jù)其尺寸用cvCreateImage()創(chuàng)建能夠存儲3通道的圖片結(jié)構(gòu)體的內(nèi)存區(qū)域啡专,并用指針變量img3chan指向它
IplImage img = img0;//可以直接賦值轉(zhuǎn)換為結(jié)構(gòu)體
IplImage *img3chan = cvCreateImage(cvGetSize(&img),img.depth, 3);
第二步是用cvCvtColor方法將img中的原始圖片數(shù)據(jù)轉(zhuǎn)化為RGB三通道的圖片险毁,并將圖片數(shù)據(jù)保存到img3chan中。
cvCvtColor(&img,img3chan,CV_RGBA2RGB);//CV_RGBA2RGB表示4通道轉(zhuǎn)成3通道
第三步是要完成位數(shù)的轉(zhuǎn)換们童,以上幾步只是完成通道數(shù)量的轉(zhuǎn)換畔况,同樣我們需要用一個方法cvCreateMat()創(chuàng)建一個新的內(nèi)存區(qū)域來作為容器來存放轉(zhuǎn)換后的結(jié)果,最后用cvConvert()完成最終轉(zhuǎn)換
CvMat *cvMat = cvCreateMat(img.height, img.width, CV_8UC3);//創(chuàng)建容器區(qū)域
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("修復(fù)后", inpainted);
// imshow("圖像掩碼",inpaintMask);
return res_imgs;
}