若是不用第三方提供的收费服务好比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…