Как размыть существующее изображение в 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:
Мое расширение
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()