如何使用Swift模糊UIImageView中的现有图像?

31

设置很简单。

  • 有一个ViewController,其中包含UIImageView并分配了一个图像。
  • 有一个UIButton,当点击时会将UIImageView中的图像模糊。

Storyboard

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var bg: UIImageView!

    @IBAction func blur(_ sender: Any) {
        let inputImage = CIImage(cgImage: (bg.image?.cgImage)!)

        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: "inputImage")
        filter?.setValue(10, forKey: "inputRadius")
        let blurred = filter?.outputImage
        bg.image = UIImage(ciImage: blurred!)
    }
}
当点击按钮时,屏幕变成白色。我不知道哪里出了问题。有人知道我哪里出错了吗?

你是在真实设备上测试还是模拟器上测试?一些 CI 过滤器(我现在正在处理遮罩模糊)在模拟器中的性能非常差(需要一分钟才能显示)。 - user7014451
请用Github链接测试验证我的答案。 - KSR
11个回答

37

您可以使用UIVisualEffect来实现模糊效果。如果您想使用CoreImage实现模糊效果,请在您的类中导入CoreImage后尝试以下代码。

var context = CIContext(options: nil)

func blurEffect() {

    let currentFilter = CIFilter(name: "CIGaussianBlur") 
    let beginImage = CIImage(image: bg.image!)
    currentFilter!.setValue(beginImage, forKey: kCIInputImageKey)
    currentFilter!.setValue(10, forKey: kCIInputRadiusKey)

    let cropFilter = CIFilter(name: "CICrop")
    cropFilter!.setValue(currentFilter!.outputImage, forKey: kCIInputImageKey)
    cropFilter!.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")

    let output = cropFilter!.outputImage 
    let cgimg = context.createCGImage(output!, from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    bg.image = processedImage
}

输出:

在此输入图片说明

注意:我建议您在真实设备上测试代码,因为模拟器在核心图像上的性能太慢了。


这个很好用。我不想使用UIVisualEffect,因为我想通过输入半径来控制模糊程度。谢谢! - Mark Moeykens
@MarkMoeykens 请查看此处以获取自定义模糊比例 https://dev59.com/x2Qn5IYBdhLWcg3wLkgd#51406290 - Jack
使用特定模糊值进行图像模糊 https://gist.github.com/afshin-hoseini/9c370268ffa4c43b0696 - Tajinder singh
尝试了所有其他的模糊建议,这个完美地解决了问题!我之前尝试的其他方法总是以奇怪的方式裁剪图像... 裁剪滤镜解决了这个问题,谢谢! - Declan Land
修改了代码以保持原始的比例和方向。如果不进行这种修改,如果原始图像是一个旋转图像,模糊后的图像将会相对于原始图像而旋转。 - Victor Engel
修改了代码以保持原始的比例和方向。如果没有这个修改,如果原始图像是旋转的,模糊图像将与原始图像相对旋转。 - undefined

31

对于那些热爱协议的人

protocol Blurable {
    func addBlur(_ alpha: CGFloat)
}

extension Blurable where Self: UIView {
    func addBlur(_ alpha: CGFloat = 0.5) {
        // create effect
        let effect = UIBlurEffect(style: .dark)
        let effectView = UIVisualEffectView(effect: effect)
        
        // set boundry and alpha
        effectView.frame = self.bounds
        effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        effectView.alpha = alpha
        
        self.addSubview(effectView)
    }
}

// Conformance
extension UIView: Blurable {}

// use
someImageview.addBlur()

8
谢谢!只有一点小问题:'protocol Blurable' 的命名可以更好一些,我相信 :) - atereshkov

8

以下是我在SWIFT 3.1中获得期望结果的方法: 希望对您有所帮助。

func blurImage(image:UIImage) -> UIImage? {
        let context = CIContext(options: nil)
        let inputImage = CIImage(image: image)
        let originalOrientation = image.imageOrientation
        let originalScale = image.scale

        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: kCIInputImageKey)
        filter?.setValue(10.0, forKey: kCIInputRadiusKey) 
        let outputImage = filter?.outputImage

        var cgImage:CGImage?

        if let asd = outputImage
        {
            cgImage = context.createCGImage(asd, from: (inputImage?.extent)!)
        }

        if let cgImageA = cgImage
        {
            return UIImage(cgImage: cgImageA, scale: originalScale, orientation: originalOrientation)
        }

        return nil
    }

好的回答,我已经点赞了,但请遵循代码风格编写您的代码。例如,这是什么:asdcgImageA。您可以简单地编写:if let outputImage = outputImage { // }。有关更多信息,请查看我使用的raywenderlich代码风格指南:https://github.com/raywenderlich/swift-style-guide#optionals - Volodymyr
工作正常,但速度较慢。 - undefined

6

2
这个几乎可以工作,但它会改变图像的大小/位置,请确保在之后裁剪图像。img.applyingGaussianBlur(sigma: radius).cropped(to: img.extent) - danfordham
2
你本来可以编辑这个答案。我刚刚做了。 :) - Victor Engel
@VictorEngel 谢谢 :) 对不起,我没有跟上这个。 - phitsch

2
一个性能良好且结果不错的解决方案是StackBlur,它使用了一种聪明的算法来高效地近似模糊:
这是高斯模糊和盒式模糊之间的折中方案。它比盒式模糊创建出更美观的模糊效果,但比我的高斯模糊实现快7倍。我称其为Stack Blur,因为这最能描述该滤镜的内部工作原理:在扫描图像时,它创建了一种移动堆栈(或者可能是一种“汉诺塔”类似的结构)颜色。这个“塔”控制着卷积核内单个像素的权重,并赋予中心像素最高的权重。速度的秘密在于该算法只需将一个新像素添加到堆栈的右侧,同时删除最左侧的像素。堆栈顶部剩余的颜色要么增加1个,要么减少1个,具体取决于它们位于堆栈的右侧还是左侧。
请查看Github上的StackBlur
有许多版本可用,也有Swift端口,但这些版本比Obj-C版本慢得多。
2019年补充:
如果要模糊的图像是远程加载的,则强烈推荐Nuke框架,该框架可以远程加载图像并直接应用模糊滤镜。它的应用类似于Android上的Glide库。虽然模糊单个图像可能很容易,但考虑到设备资源限制,模糊多个图像(例如在集合视图中)就不那么简单了。Nuke高度优化了远程图像加载、缓存和处理。它还可以在多个方面进行扩展。从比较可用的远程图像加载框架来看,我认为Nuke是2019年11月份最稳定、最先进的框架。

2

请使用以下内容:

 import UIKit

    class ViewController: UIViewController {

        @IBOutlet weak var bgImageView: UIImageView!
        @IBOutlet weak var blurButton: UIButton!


        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }


        @IBAction func blurButtonTapped(_ sender: Any) {

                let inputImage = CIImage(cgImage: (self.bgImageView.image?.cgImage)!)
                let filter = CIFilter(name: "CIGaussianBlur")
                filter?.setValue(inputImage, forKey: "inputImage")
                filter?.setValue(10, forKey: "inputRadius")
                let blurred = filter?.outputImage

                var newImageSize: CGRect = (blurred?.extent)!
                newImageSize.origin.x += (newImageSize.size.width - (self.bgImageView.image?.size.width)!) / 2
                newImageSize.origin.y += (newImageSize.size.height - (self.bgImageView.image?.size.height)!) / 2
                newImageSize.size = (self.bgImageView.image?.size)!

                let resultImage: CIImage = filter?.value(forKey: "outputImage") as! CIImage
                let context: CIContext = CIContext.init(options: nil)
                let cgimg: CGImage = context.createCGImage(resultImage, from: newImageSize)!
                let blurredImage: UIImage = UIImage.init(cgImage: cgimg)
                self.bgImageView.image = blurredImage
        }

    }

输出:

在此输入图片描述

Github链接:

https://github.com/k-sathireddy/ImageBlurEffect


1

我的扩展

extension UIImage {
    
    func blurImage(radius: CGFloat = 10) -> UIImage? {
        guard let cgImage = cgImage else { return nil }
        let inputCIImage = CIImage(cgImage: cgImage)
        let context = CIContext(options: nil)
        
        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: kCIInputImageKey)
        filter?.setValue(radius, forKey: kCIInputRadiusKey)
        let outputImage = filter?.outputImage
        
        if let outputImage = outputImage,
            let cgImage = context.createCGImage(outputImage, from: inputImage.extent) {
            
            return UIImage(
                cgImage: cgImage,
                scale: scale,
                orientation: imageOrientation
            )
        }
        return nil
    }
 }

0

检查是否有东西为空。我遇到了类似的问题,但在我的情况下,我没有创建CIImage的新实例,因此图像.ciimage为空。


0
我在一个NSObject类中实现了模糊效果,这样我就可以在整个项目中轻松地使用这个方法。
class Helper: NSObject
{
    class func addBlurView(_ inView : UIView) -> UIVisualEffectView
    {
        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)

        //always fill the view
        blurEffectView.frame = inView.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        blurEffectView.alpha = 0.5

        return blurEffectView
    }
}

在ViewController中,我创建了一个UIVisualEffectView的对象。然后调用了辅助类的方法来添加模糊效果。
import UIKit

class ViewController: UIViewController
{
   var blurEffectView : UIVisualEffectView!
    override func viewDidLoad() {
        super.viewDidLoad()

      blurEffectView = Helper.addBlurView((imgView)!)
      self.imgView.addSubview(blurEffectView)
}

-1

你可以通过 UIBlurEffectUIVisualEffectView 添加模糊效果:

@IBAction func blur(_ sender: Any) {

    let darkBlur = UIBlurEffect(style: UIBlurEffectStyle.dark) 
    let blurView = UIVisualEffectView(effect: darkBlur)
    blurView.frame = bg_imagview.bounds
    blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    bg_imagview.addSubview(blurView)

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接