若是不用第三方提供的收費服務好比face++的摳圖,想到的大體步驟應該是ios
1:找一個白色的背景牆,衣服最好和背景牆區分開來 2:而後扣出來 3:最後和其餘底色或者圖片融合到一塊兒git
iOS方面安裝方法如今能夠用Pods 進來,值得注意的是因爲須要C++ 代碼和iOS混編,因此當前文件改成.mm後綴,並引入相應的頭文件例如:github
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
複製代碼
1:基於交互式界面由用戶選擇前景區域; 2:定義一個單通道的輸出掩碼,0爲背景,1爲前景,2爲可能的背景,3爲可能的前景; 3:grabCut摳圖;將輸出結果與可能的前景做比較獲得可能的前景; 4:定義三通道的結果圖像; 5:從原圖中拷貝可能的前景到結果圖像;算法
grabCut( InputArray img, InputOutputArray mask, Rect rect,
InputOutputArray bgdModel, InputOutputArray fgdModel,
int iterCount, int mode = GC_EVAL );
複製代碼
img:輸入原圖像;bash
mask:輸出掩碼;框架
rect:用戶選擇的前景矩形區域;ide
bgModel:輸出背景圖像;函數
fgModel:輸出前景圖像;post
iterCount:迭代次數;ui
知道大體步驟開始幹,因爲C++ image 和 iOS image表示方法不同,因此大體有下面兩個轉化方法
-(UIImage *)UIImageFromCVMat:(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)cvMatFromUIImage:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC4); // 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), image.CGImage);
CGContextRelease(contextRef);
return cvMat;
}
複製代碼
注意:網上找的一些其餘平臺的寫法在iOS 中要加上cv:: 前綴,好比變量的聲明或者方法的調用。
-(UIImage*) doGrabCutWithMask:(UIImage*)sourceImage maskImage:(UIImage*)maskImage iterationCount:(int) iterCount{
cv::Mat img=[self cvMatFromUIImage:sourceImage];
cv::cvtColor(img , img , CV_RGBA2RGB);
cv::Mat1b markers=[self cvMatMaskerFromUIImage:maskImage];
cv::Rect rectangle(0,0,0,0);
// GrabCut segmentation
cv::grabCut(img, markers, rectangle, bgModel, fgModel, iterCount, cv::GC_INIT_WITH_MASK);
cv::Mat tempMask;
cv::compare(mask,cv::GC_PR_FGD,tempMask,cv::CMP_EQ);
// Generate output image
cv::Mat foreground(img.size(),CV_8UC3,
cv::Scalar(255,255,255));
tempMask=tempMask&1;
img.copyTo(foreground, tempMask);
UIImage* resultImage=[self UIImageFromCVMat:foreground];
return resultImage;
}
複製代碼
1:從iOS平臺導入image轉化爲C++ 的結構 2:調用grabCut摳圖 3:比較mask的值爲可能的前景像素才輸出到mask中 4:產生輸出圖像 5:將原圖區域copy到foreground中 6:轉化爲iOS平臺的image結構
因爲背景色和前景色有明顯對比因此看着有鋸齒的邊緣,解決思路是把當前圖像和背景圖融合的時候邊緣作腐蝕加高斯模糊處理。 總結下上述作法適合比較規範的拍照姿式,若是不規範就會很難看,因此打算放棄這個思路。
仍是用OpenCV這個框架用了裏面的inpaint修復算法。
1:標定噪聲的特徵,使用cv2.inRange二值化標識噪聲對圖片進行二值化處理,具體代碼:cv2.inRange(img, np.array([240, 240, 240]), np.array([255, 255, 255])),把[240, 240, 240]~[255, 255, 255]之外的顏色處理爲0; 2:使用inpaint方法,把噪聲的mask做爲參數,推理並修復圖片;
cv::Mat img=[self cvMatFromUIImage:[UIImage imageNamed:@"test.jpg"]];
cv::cvtColor(img , img , CV_RGBA2RGB);
// UIImage *testImage = [UIImage imageNamed:@"test.jpg"];
// UIImage *reslutsImage = [testImage WaterMarkDelete:CGRectMake(0, 0, 320, 320)];
//
//
// //獲取mask
//
// cv::Mat mask;
//
// cv::inRange(img, cv::Scalar(0, 0, 250), cv::Scalar(0, 0, 255), mask);
//
//
//
// // 修復
//
// cv::Mat dst;
//
// cv::inpaint(img, mask, dst, 3, CV_INPAINT_TELEA);
//
// UIImage *resultImage =[self UIImageFromCVMat:dst];
// UIImageWriteToSavedPhotosAlbum(resultImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
//
cv::Mat wm; // 水印文字
cv::inRange(img, cv::Scalar(204, 115, 122), cv::Scalar(246, 103, 115), wm);
UIImage *wmImage =[self UIImageFromCVMat:wm];
UIImageWriteToSavedPhotosAlbum(wmImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
//
// 形態學操做
cv::Mat kernel = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));
morphologyEx(wm, wm, MORPH_DILATE, kernel, cv::Point(-1, -1), 2);
// 去水印結果
cv::Mat tywwm;
inpaint(img, wm, tywwm, 3, CV_INPAINT_NS);
UIImage *resultImage =[self UIImageFromCVMat:tywwm];
UIImageWriteToSavedPhotosAlbum(resultImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
複製代碼
圖像形態學操做膨脹獲得的是第二張的圖片,若是水印的顏色是其餘顏色則須要調整cv2.inRange 顏色範圍。
因爲時間有限我感受沒個一個月時間是不能達到產品的效果,因此這個方式我也暫時放棄,之後能夠做爲本身的一個App來作。
1:好比iOS平臺的coreimage,能夠作直播主播的綠幕替換,其實主播背景都是後期處理上去的,這樣的狀況比較適合比較單純的純色,若是有其餘亮度的效果,可能效果不佳給個連接juejin.im/post/5a3a10…。
2:除去水印谷歌貌似研究出來了一個新的算法能夠比PS還要高效的處理去掉水印,www.jiqizhixin.com/articles/20…。
3:還有一個不錯的框架CPUImage對圖片和視頻的處理也是一個很強大的框架
4:推薦一個不錯的圖片處理系列教程:www.cnblogs.com/Imageshop/
參考連接:
cloud.tencent.com/developer/a…