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

Установка проста.

  • ViewController с UIImageView, которому назначено изображение.
  • Кнопка UIButton, которая при нажатии размывает изображение в 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!)
    }
}

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


person Mark Moeykens    schedule 15.12.2016    source источник
comment
Вы тестируете на реальном устройстве или симуляторе? Некоторые фильтры CI (я сейчас работаю над маскированным размытием) имеют жалкую производительность (подумайте о том, что на отображение требуется минута) в симуляторе.   -  person dfd    schedule 15.12.2016
comment
Пожалуйста, проверьте мой ответ со ссылкой на Github, чтобы проверить.   -  person KSR    schedule 15.12.2016


Ответы (11)


Вы можете просто использовать 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 слишком низкая.

person Joe    schedule 15.12.2016
comment
Это сработало отлично. Я не хотел использовать UIVisualEffect, потому что хотел контролировать уровень размытия с помощью inputRadius. Спасибо! - person Mark Moeykens; 15.12.2016
comment
@MarkMoeykens См. здесь пользовательский масштаб размытия stackoverflow.com/a/51406290/7576100 - person Jack; 18.07.2018
comment
размытие с определенным значением размытия gist.github.com/afshin-hoseini/9c370268ffa4c43b0696 - person Tajinder singh; 18.11.2020
comment
Пробовал все другие предложения по размытию, и это сработало отлично! Другие попытки, которые я использовал, всегда обрезали изображение странным образом ... фильтр обрезки исправил это, спасибо! - person Declan Land; 12.01.2021

для тех, кто ❤️ протоколирует

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()
person kaushal.exe    schedule 16.08.2017
comment
Спасибо! Только одна гнида: «протокол Blurable», я думаю, немного лучше именовать :) - person atereshkov; 02.09.2019

Вот как я получил ожидаемый результат в 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
    }
person Md Milan Mia    schedule 11.07.2017
comment
хороший ответ, я проголосовал, но, пожалуйста, следуйте стилю кода при написании кода. Например, что это: asd или cgImageA. Вы можете просто написать: if let outputImage = outputImage { // }. Для получения дополнительной информации проверьте код Raywenderlich. Стиль, который я использую: github.com/raywenderlich/swift-style- руководство#опционально - person Vlad; 05.12.2018

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

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

Посетите StackBlur на Github.

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

Дополнение 2019:

Если изображения для размытия загружаются удаленно, я настоятельно рекомендую инфраструктуру Nuke, которая удаленно загружает изображения и может применить фильтр размытия из коробки. Это приложение сравнимо с библиотекой Glide на Android. Хотя размыть одно изображение может быть легко, размыть несколько изображений — например, в представлении коллекции — с учетом ограничений ресурсов устройства не так тривиально. Nuke оптимизирован для удаленной загрузки, кэширования и обработки изображений. Он также расширяем в нескольких аспектах. Сравнивая доступные фреймворки для удаленной загрузки изображений, я думаю, что Nuke является наиболее стабильным и продвинутым для этой цели по состоянию на ноябрь 2019 года.

person Manuel    schedule 09.04.2018

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

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

 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
        }

    }

Вывод:

введите здесь описание изображения

Ссылка на гитбуб:

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

person KSR    schedule 15.12.2016

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

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
    }
 }
person RomanV    schedule 02.07.2020

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

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

person Pedro Ortiz    schedule 21.11.2019

Вы можете добавить эффект размытия с помощью 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)

}
person Bhavin Ramani    schedule 15.12.2016

Привет всем ЛЕНИВЫМ парням, таким как я.

Просто добавьте SwifterSwift с какао-стручками.

Импорт SwifterSwift.

import SwifterSwift

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

someImageView.blur()
person LeoNard    schedule 04.02.2020