最近用到了高斯模糊,谷歌了一下,发现挺多现成的例子,本来只是收藏一下网址的,但是在用的过程中,发现了一点问题,索性就把自己使用的汇总下,以后好参考。主要代码全部来源于参考链接里面。
一、发现的问题
在使用vImage
渲染高斯模糊的时候,参考文章一中,测试发现如果仅仅使用静态图的时候,的确会模糊,但是仔细看的话,发现背景颜色居然变了,看评论的确也有其他人碰到。
所以就继续搜索,在知乎上面搜到了另外一个文章说高斯模糊的开销时,又附了一段代码,使用是OK的,就是参考文章二中的例子,所以就在项目中使用了。
当今天写这个例子的时候,居然发现不知道什么原因,参考文章一中的图片背景颜色是正常的,二中的背景颜色不对了,最终终于找到了一个可用的方案,总结下
二、高斯模糊
2.1、使用CoreImage进行高斯模糊
/**
使用CoreImage进行高斯模糊
@param image 需要模糊的图片
@param blur 模糊的范围 可以1~99
@return 返回已经模糊过的图片
*/
+(UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur
{
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage= [CIImage imageWithCGImage:image.CGImage];
//设置filter
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey]; [filter setValue:@(blur) forKey: @"inputRadius"];
//模糊图片
CIImage *result=[filter valueForKey:kCIOutputImageKey];
CGImageRef outImage=[context createCGImage:result fromRect:[result extent]];
UIImage *blurImage=[UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return blurImage;
}
2.2、使用Accelerate中的vImage进行高斯模糊
/**
使用vImage进行高斯模糊
@param image 需要模糊的图片
@param blur 模糊的范围 0~1
@return 返回已经模糊过的图片
*/
+(UIImage*)imageBlurImage:(UIImage *)image WithBlurNumber:(CGFloat)blur
{
// NSInteger boxSize = (NSInteger)(10 * 5);
NSData *imageData = UIImageJPEGRepresentation(image, 1); // convert to jpeg
UIImage* destImage = [UIImage imageWithData:imageData];
if (blur < 0.f || blur > 1.f) {
blur = 0.5f;
}
int boxSize = (int)(blur * 40);
boxSize = boxSize - (boxSize % 2) + 1;
CGImageRef img = destImage.CGImage;
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
//create vImage_Buffer with data from CGImageRef
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
//create vImage_Buffer for output
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
if(pixelBuffer == NULL)
NSLog(@"No pixelbuffer");
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
// Create a third buffer for intermediate processing
void *pixelBuffer2 = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
vImage_Buffer outBuffer2;
outBuffer2.data = pixelBuffer2;
outBuffer2.width = CGImageGetWidth(img);
outBuffer2.height = CGImageGetHeight(img);
outBuffer2.rowBytes = CGImageGetBytesPerRow(img);
//perform convolution
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
(CGBitmapInfo)kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean up
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
free(pixelBuffer2);
CFRelease(inBitmapData);
CGImageRelease(imageRef);
return returnImage;
}
2.3、高斯模糊总结
当然参考文章中说使用GPUImage这个库也可以搞定,但是对于模糊这个计算量大的操作来说,借用知乎上面的总结
- CoreImage 的帧数会随着模糊大小而降低,cpu也蛮高;
- Accelerate 的模糊是最靠谱的,速度和效果都非常完美,同时会占用更高的cpu;
所以还是使用Accelerate的vImage这个方案比较好
三、毛玻璃
毛玻璃是ios8.0之后的一个效果,可以使用UIVisualEffectView
来实现,就是在UIImageView上面加一个view。
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
effectView.frame = CGRectMake(0, 0, _imgView.frame.size.width*0.5, _imgView.frame.size.height);
[_imgView addSubview:effectView];
UIBlurEffectStyle有几个不同的样式,可以自己调整使用
typedef NS_ENUM(NSInteger, UIBlurEffectStyle) {
UIBlurEffectStyleExtraLight,
UIBlurEffectStyleLight,
UIBlurEffectStyleDark,
UIBlurEffectStyleExtraDark __TVOS_AVAILABLE(10_0) __IOS_PROHIBITED __WATCHOS_PROHIBITED,
UIBlurEffectStyleRegular NS_ENUM_AVAILABLE_IOS(10_0), // Adapts to user interface style
UIBlurEffectStyleProminent NS_ENUM_AVAILABLE_IOS(10_0), // Adapts to user interface style
} NS_ENUM_AVAILABLE_IOS(8_0);
四、Demo下载
Github下载:https://github.com/DamonHu/HudongBlogDemo/tree/master/ImgBlur
Gitee下载:https://gitee.com/DamonHoo/HudongBlogDemo/tree/master/ImgBlur
五、Demo效果
六、参考文章
版权属于:东哥笔记 - DongGe.org
本文链接:https://dongge.org/blog/601.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!
2 条评论
UIVisualEffectView 是 iOS8.0 之后加入的.
恩啊,多谢指正,枚举那里写的8.0୧(๑•̀⌄•́๑)૭