GPUImage动画高斯模糊滤镜

Nik*_*rma 2 objective-c gpuimage

我使用GPUImage高斯模糊滤镜来模糊静止图像.我想将模糊大小与UI元素联系起来,当用户更改元素时,我会模糊图片.我现在正在做的方法是在发生重大(> 0.25)更改时更改blurSize,重新应用过滤器并将新图像设置为imageView动画.

有没有更有效的方式让我这样做?

在iPhone 5上,虽然性能不是很迟钝,但它也不是非常流畅(但也许这是因为这个操作太昂贵而不能超级流畅).

Adl*_*ler 7

有趣的问题.最好的办法是预先计算和在你的范围内一对夫妇的模糊尺度呈现CGImages,然后用两个堆叠的UIImageViews,与一个在顶部显示的虚化副本,但部分透明.例如,如果你在半径1,2,3,...,10渲染的模糊,你想显示3.7,你会显示在顶部底部的图像4图像3,在70%的不透明度.

// Created in answer to Nikhil Varma's question at http://stackoverflow.com/questions/18804668/gpuimage-animated-gaussian-blur-filter
#import "GPUImage.h"
#define BLUR_STEP 2.
@interface AHViewController : UIViewController

@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (nonatomic) CGFloat blurRadius;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) GPUImageGaussianBlurFilter *blurFilter;
@property (nonatomic, strong) NSCache *blurredImageCache;
@property (nonatomic, strong) dispatch_queue_t blurQueue;
@property (nonatomic, strong) NSMutableSet *blurAmountsBeingRendered;
@end

@implementation AHViewController

-(void)viewDidLoad {
    [super viewDidLoad];
    self.image = [UIImage imageNamed:@"ph.jpg"];
    self.blurFilter = [GPUImageGaussianBlurFilter new];
    self.blurredImageCache = [NSCache new];
    self.blurQueue = dispatch_queue_create("Image Blur Queue", DISPATCH_QUEUE_SERIAL);
    self.blurAmountsBeingRendered = [NSMutableSet set];
    self.blurRadius = 1.0;
}
- (IBAction)sliderDidMove:(UISlider *)sender {
    self.blurRadius = 10 * sender.value;
}
-(void)setBlurRadius:(CGFloat)blurRadius {
    _blurRadius = blurRadius;
    CGFloat smaller = self.blurRadius - fmodf(self.blurRadius, BLUR_STEP);
    [self asyncGenerateImageWithBlurAmount:smaller];
    CGFloat larger = smaller + BLUR_STEP;
    [self asyncGenerateImageWithBlurAmount:larger];

}
-(UIImage *)cachedImageWithBlurAmount:(CGFloat)blur {
    return [self.blurredImageCache objectForKey:@(blur)];
}
-(void)asyncGenerateImageWithBlurAmount:(CGFloat)blur {
    // This image is already available.
    if([self.blurredImageCache objectForKey:@(blur)]) {
        [self imageIsAvailableWithBlur:blur];
        return;
    }
    // There's already a render going on for this. Just return.
    if([self.blurAmountsBeingRendered containsObject:@(blur)])
        return;

    // Start a render
    [self.blurAmountsBeingRendered addObject:@(blur)];
    dispatch_async(self.blurQueue, ^{
        self.blurFilter.blurSize = blur;
        UIImage *result = [self.blurFilter imageByFilteringImage:self.image];
        [self.blurredImageCache setObject:result forKey:@(blur)];
        [self.blurAmountsBeingRendered removeObject:@(blur)];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self imageIsAvailableWithBlur:blur];
        });
    });
}

-(void)imageIsAvailableWithBlur:(CGFloat)blurAmount {
    CGFloat smaller = self.blurRadius - fmodf(self.blurRadius, BLUR_STEP);
    CGFloat larger = smaller + BLUR_STEP;

    UIImage *sharperImage = [self cachedImageWithBlurAmount:smaller];
    UIImage *blurrier = [self cachedImageWithBlurAmount:larger];
    if(sharperImage && blurrier) {
        if(![self.imageView.image isEqual:sharperImage])
            self.imageView.image = sharperImage;
        if(![self.imageView2.image isEqual:blurrier]) {
            self.imageView2.image = blurrier;
        }
        self.imageView2.alpha = (self.blurRadius - smaller) / BLUR_STEP;
    }
}


@end
Run Code Online (Sandbox Code Playgroud)

  • 更好的解决方案是避免使用UIImageView作为模糊图像的输出目标.从框架中提取UIImage有很多开销,并且在将它分配给UIImageView时也有类似的开销.相反,模糊应该直接渲染到GPUImageView,以便所有这些都保留在GPU上.这是一条更快的路线. (3认同)
  • @NikhilVarma叠加的imageView方法可以让我们估算出未计算的模糊量.假设用户将滑块设置为3.71.如果我们已经在4和3处保存了模糊图像,我们可以非常快速地将它们混合在一起,而不是计算出一个全新的模糊图像.如果用户然后拖动到3.72,我们只需改变混合比例.布拉德错了 - GPUImageView在这里根本无法实现流动性,因为高斯模糊非常昂贵. (2认同)