【问题标题】:How to blur an existing image in a UIImageView with Swift?如何使用 Swift 模糊 UIImageView 中的现有图像?
【发布时间】:2017-04-30 14:32:52
【问题描述】:

设置很简单。

  • 带有 UIImageView 的 ViewController 已分配图像。
  • 单击时会模糊 UIImageView 中的图像的 UIButton。

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 过滤器(我现在正在处理蒙版模糊)在模拟器中的性能很差(想想需要一分钟才能显示)。
  • 请用 Github 链接检查我的答案以进行测试..

标签: ios swift uiimageview cifilter ciimage


【解决方案1】:

您可以简单地使用UIVisualEffect 来实现模糊效果。当您尝试使用 CoreImage 实现模糊效果时。请在 import 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
}

输出:

注意:建议您在真机上测试代码,因为模拟器在 coreImage 上的性能太慢了。

【讨论】:

  • 这很好用。我不想使用UIVisualEffect,因为我想用 inputRadius 控制模糊程度。谢谢!
  • @MarkMoeykens 请在此处查看自定义模糊比例stackoverflow.com/a/51406290/7576100
  • 尝试了所有其他模糊建议,效果很好!我使用的其他尝试总是以一种奇怪的方式裁剪图像.. 裁剪过滤器解决了这个问题,谢谢!
【解决方案2】:

对于那些❤️协议的人

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

extension Bluring 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: Bluring {}

// use
someImageview.addBlur()

【讨论】:

  • 谢谢!只有一个尼特:'protocol Blurable',我相信更好的命名:)
【解决方案3】:

这是我在 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 代码样式:github.com/raywenderlich/swift-style-guide#optionals
【解决方案4】:

CoreImage 中实际上有一个方便的实现 https://developer.apple.com/documentation/coreimage/ciimage/1645897-applyinggaussianblur

extension UIImage {

func blur(_ radius: Double) -> UIImage? {
    if let img = CIImage(image: self) {
        return UIImage(ciImage: img.applyingGaussianBlur(sigma: radius))
    }
    return nil
}

【讨论】:

  • 这几乎可以工作,但它会改变图像大小/位置,请务必在之后裁剪 img。 img.applyingGaussianBlur(sigma: radius).cropped(to: img.extent)
【解决方案5】:

StackBlur 是一个性能良好且结果不错的解决方案,它使用了一种巧妙的算法,可以有效地逼近模糊:

这是高斯模糊和方框模糊之间的一种折衷方案 比 Box Blur 更好看的模糊,但比我的快 7 倍 高斯模糊实现。我把它叫做 Stack Blur 因为这个 最好地描述了这个过滤器是如何在内部工作的:它创建了一种 移动颜色的堆栈(或者可能是“河内塔”类型的结构) 同时扫描图像。这个“塔”控制权重 卷积核内的单个像素,并给出像素 在中心的重量最高。速度的秘密在于 算法只需在堆栈的右侧添加一个新像素 同时移除最左边的像素。剩下的颜色 在堆栈的最顶层被添加或减少 一,取决于它们是在右侧还是左侧 堆栈。

查看StackBlur on Github

那里有很多版本,还有 Swift 端口,但这些版本比 Obj-C 版本慢很多。

2019 年新增:

如果要模糊的图像是远程加载的,我强烈推荐Nuke 框架,它可以远程加载图像并且可以开箱即用地应用模糊过滤器。它的应用程序可与 Android 上的 Glide 库相媲美。虽然模糊一张图像可能很容易,但在考虑设备资源限制的同时模糊许多图像(例如在集合视图中)就不那么简单了。 Nuke 针对远程图像加载、缓存和处理进行了高度优化。它还可以在多个方面进行扩展。通过比较可用的远程图像加载框架,我认为 Nuke 是截至 2019 年 11 月为止最稳定和最先进的。

【讨论】:

    【解决方案6】:

    使用这个:

     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
            }
    
        }
    

    输出:

    Gitbub 链接:

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

    【讨论】:

      【解决方案7】:

      我的扩展

      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
          }
       }
      

      【讨论】:

        【解决方案8】:

        我在一个 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)
        }
        

        【讨论】:

          【解决方案9】:

          检查是否有什么东西是零。我遇到了类似的问题,但在我的情况下,我没有创建 CIImage 的新实例,因为 image.ciimage 将为零。

          【讨论】:

            【解决方案10】:

            您可以通过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)
            
            }
            

            【讨论】:

              【解决方案11】:

              嘿,所有像我一样的懒人。

              只需将 SwifterSwift 与 cocoapods 添加即可。

              导入 SwifterSwift。

              import SwifterSwift
              

              像下面那样模糊你的图像视图。

              someImageView.blur()
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-11-12
                • 2020-09-08
                • 2012-09-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多