Как размыть существующее изображение в UIImageView с Swift?

Настройка проста.

  • ViewController с UIImageView, которому назначено изображение.
  • Кнопка UIB, которая при щелчке размывает изображение в UIImageView.

Раскадровка

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

Когда кнопка нажата, экран просто становится белым. Не могу понять, что я делаю не так. Кто-нибудь знает, что я делаю не так?

7 ответов

Решение

Вы могли бы просто использовать UIVisualEffect добиться эффекта размытия. Как вы пытаетесь добиться эффекта размытия, используя CoreImage.Try ниже код после 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 слишком низкая.

Для тех кто ❤️ протоколы

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()

Вот как я получил ожидаемый результат в 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
    }

На самом деле есть удобная реализация прямо в CoreImagehttps://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
}

Решения, использующие UIVisualEffectView или же CIFilter иметь ужасную производительность или плохие результаты (создавая размытую яркую границу вокруг изображения, как можно увидеть в ответе Джо) или оба варианта.

Одно из самых эффективных решений с достойными результатами StackBlur который использует умный алгоритм, который эффективно приближает размытие:

Это компромисс между Gaussian Blur и Box Blur. Он создает гораздо более привлекательные пятна, чем Box Blur, но в 7 раз быстрее, чем моя реализация Gaussian Blur. Я назвал это Stack Blur, потому что это лучше всего описывает, как этот фильтр работает внутри: он создает некий движущийся стек (или, возможно, структуру типа "Ханойская башня") цветов при сканировании изображения. Эта "башня" контролирует вес отдельных пикселей в ядре свертки и дает пикселю в центре самый большой вес. Секрет скорости заключается в том, что алгоритм просто должен добавить один новый пиксель к правой стороне стека и в то же время удалить самый левый пиксель. Остальные цвета на верхнем слое стека либо добавляются, либо уменьшаются на единицу, в зависимости от того, находятся ли они справа или слева от стека.

Проверьте StackBlur на Github.

Существует множество версий, включая порты Swift, но они значительно медленнее, чем версии Obj-C.

Использовать этот:

 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

Мое расширение

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

Я сделал размытие в классе 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)
}

Проверьте, не приближается ли что-то к нулю. У меня была аналогичная проблема, но в моем случае я не создавал новый экземпляр CIImage из-за того, что image.ciimage возвращался к нулю.

Вы можете добавить эффект размытия, UIBlurEffect а также UIVisualEffectView:

@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)

}

Привет всем ленивым парням вроде меня.

Просто добавьте SwifterSwift с cocoapods.

Импортируйте SwifterSwift.

import SwifterSwift

Размытие изображения, как показано ниже.

someImageView.blur()
Другие вопросы по тегам