繁体   English   中英

如何在iOS中设置/输出高斯模糊效果?

[英]How do I animate in/out a gaussian blur effect in iOS?

对于整个iOS 7的感觉,我想将模糊效果应用到屏幕的特定部分以对其进行模糊处理,但我不想立即投射模糊,我想要将其设置为动画并将其设置为动画用户几乎看到应用的模糊效果。

几乎就像在Photoshop中一样,你将高斯模糊值从0改为10,而不是一次性改为0到10。

我已经尝试了一些解决方案,最流行的建议是简单地将模糊视图放在非模糊视图的顶部,然后降低模糊视图的alpha值。

没关系 ,但不是很令人愉悦,因为没有过渡,它只是一个叠加。 例:

在此输入图像描述

什么是实现这种效果的更好方法? 我熟悉GPUImage ,但不知道如何用它完成它。

如果我可以控制它的模糊百分比也很好,所以它可以从用户交互应用。 (例如:用户拖动中途,模糊应用一半等)

使用iOS 9及更高版本,您可以为视觉效果视图设置动画效果:

[UIView animateWithDuration:0.3 animations: ^ {
    visualEffectView.effect = blurEffect;
} completion:nil];

这将实现动画模糊半径的预期效果。


我认为如果你从非模糊视图动画交叉淡化 - >模糊视图,它将是令人愉快的。 您需要在非模糊视图的顶部为模糊视图的显示设置动画。

我们假设blurView是包含模糊效果的视图。

以下是如何完成动画过渡的两个示例:

[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
    [self.view addSubview:blurView];
} completion:nil];

这里我假设已经设置了blurView ,并且只是在动画中将添加转换为子视图。

您也可以通过不同的方式实现此目的:

blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
    blurView.alpha = 1.0f;
} completion:nil];

在这里,我使模糊视图透明并为其外观设置动画。 请注意,使用此方法将无法使用hidden ,因此您要使用alpha属性。


如果您希望以交互方式控制模糊量,下面是一个如何实现的示例:

首先创建要模糊的视图的图像:

UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();

保留此图片。 如果视图已更改,您只想以类似的方式重绘。 否则,您应该重复使用此图像,因为绘制层次结构的成本很高。

现在,当您需要模糊时,请使用以下代码:

CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];    
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"]; 
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"]; 
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the 
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"]; 
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];

inputRadius输入用于设置执行的模糊量。 如果你动画这个,你将获得互动的感觉。

但我仍然认为前一种方法更容易,并且对用户来说感觉很好。

这在OS X上很容易,其中一个视图可以对其后面的视图产生影响,并且处理器功能强大且速度快。 但是,在iOS上,没有视图合成滤镜,模糊需要一些时间:你不能像动画的帧一样快速地重复,实时。 因此需要某种形式的妥协。

但是,如果您事先知道想要模糊的是什么,则可以使用模糊渐变来准备一系列图像:没有模糊,有点模糊,有点模糊,等等。 然后组装图像并“播放”它们作为动画UIImageView的“帧”。

然而,这不是我实际建议的。 我要做的是准备模糊图像和非模糊图像,并使用CIDissolveTransition从非模糊图像溶解到模糊图像。 不,它与逐渐应用模糊不同,但它在计算上很便宜,并且是工具箱中最好的“溶解”效果。

我很少建议现成的编码问题解决方案。 但是,在这种情况下,我会全心全意地推荐LiveFrost 它是一个非常可靠的UIView子类,专门用于复制流行的iOS 7高斯模糊效果。

我还鼓励您阅读作者的博客,了解他对本课程的设计决策。 自从iOS 7发布以来,我已经在这个主题上做了很多研究,而且我对这段代码实际上是ZERO COMPLAINTS。

它甚至还有开箱即用的模糊动画! 祝你好运 :)

我开发了一个小项目,它使用GPUImage进行实时模糊,具有可变模糊半径和帧速率( MSLiveBlur ) - 这听起来就像你需要的那样。

在示例应用程序中,我有一个滑块可以增加/减少模糊级别以响应用户操作,正如您在问题中提到的那样。 如果您想在没有用户交互的情况下为其设置动画,您可以制作一个计时器,缓慢增加模糊半径,直到达到最终值。 但是,您无法将CoreAnimation与此解决方案一起使用。

[[MSLiveBlurView sharedInstance] setBlurInterval:0.2];
[[MSLiveBlurView sharedInstance] blurRect:someView.frame];

// Count x from 0 to your final radius
[MSLiveBlurView sharedInstance].blurRadius = x;

这是一个可用于使用预先计算的图像为模糊设置动画的功能。 你说你熟悉GPUImage所以我用它(但它也适用于简单的模糊算法)。

有了这个,你可以动画实时 真实模糊用1-2%的CPU的成本

// configuration
let imageCount: Int = 10
let blurMax: Float = 40.0
// keep images in memory
var currentIdx: Int = 0
var imgs: [UIImage] = []

// func that create the precomputed images with GPUImage (call it in the viewDidLoad for example)
func initBlur() {
    let blur = GaussianBlur()
    let myImage: UIImage = UIImage(named: "your_image")!
    let pictureInput = PictureInput(image: myImage)
    let pictureOutput = PictureOutput()
    pictureOutput.onlyCaptureNextFrame = false

    pictureOutput.imageAvailableCallback = { image in
        self.imgs.append(image)
    }

    pictureInput --> blur --> pictureOutput

    for i in 0...imageCount {
        blur.blurRadiusInPixels = (Float(i) / Float(imageCount)) * blurMax
        pictureInput.processImage(synchronously: true)
    }
}

// function that return the correct image from the image set with a blur percentage from a value between 0 and 1 where 0 = no blur and 1 full blurred.
func getBlurredImage(value: Float) -> UIImage? {
    // return nil if there isn't precompiled images
    if imgs.count == 0 {
        return nil
    }

    // get the desired blurred image index
    let idx = Int(value * Float(imageCount - 1))
    // if the index changed, check the correctness of the index
    if currentIdx != idx {
        if idx < 0 {
            currentIdx = 0
        }
        else if idx >= imgs.count {
            currentIdx = imageCount - 1
        }
        else {
            currentIdx = idx
        }
    }
    return imgs[currentIdx]
}

就是这样,接下来你可以使用它,例如使用计时器或scrollViewDidScroll函数,例如:

imageView.image = getBlurredImage(value: yOffset / height)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM