在iOS7中创建模糊效果

26

我已经搜索了几个小时,仍然无法找到这个问题的答案。当我按下“按钮”时,我想要为图像添加高斯模糊效果。用户会添加这个图像。

我根据SO和其他网站的来源创建了一个“按钮”操作。但它无法正常工作。我做错了什么?任何代码都将不胜感激。这是我的“按钮”操作:

- (IBAction)test:(id)sender {
    CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
    [gaussianBlurFilter setValue:imageView.image forKey: @"inputImage"];
    [gaussianBlurFilter setValue:[NSNumber numberWithFloat: 10] forKey: @"inputRadius"];
}

如果您需要我做过的其他任何事情来回答这个问题,请告诉我:D

这是我的用户界面

6个回答

74

三个观察点:

  1. 您需要将inputImage设置为来自UIImageCIImage

[gaussianBlurFilter setValue:[CIImage imageWithCGImage:[imageView.image CGImage]] forKey:kCIInputImageKey];
我看不到你取出outputImage的部分,例如:
CIImage *outputImage = [gaussianBlurFilter outputImage];
所以,把它们放在一起:
  • 你可能想将那个CIImage转换回UIImage

  • 因此,将所有内容组合在一起:

    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlurFilter setDefaults];
    CIImage *inputImage = [CIImage imageWithCGImage:[imageView.image CGImage]];
    [gaussianBlurFilter setValue:inputImage forKey:kCIInputImageKey];
    [gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey];
    
    CIImage *outputImage = [gaussianBlurFilter outputImage];
    CIContext *context   = [CIContext contextWithOptions:nil];
    CGImageRef cgimg     = [context createCGImage:outputImage fromRect:[inputImage extent]];  // note, use input image extent if you want it the same size, the output image extent is larger
    UIImage *image       = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    

    另外,如果您前往WWDC 2013示例代码(需要付费的开发者订阅),并下载iOS_UIImageEffects,则可以获取UIImage+ImageEffects类别。该类别提供了一些新方法:


    - (UIImage *)applyLightEffect;
    - (UIImage *)applyExtraLightEffect;
    - (UIImage *)applyDarkEffect;
    - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;
    - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;
    

    因此,要使图像模糊并变亮(产生“毛玻璃”效果),您可以执行以下操作:

    UIImage *newImage = [image applyLightEffect];
    

    有趣的是,苹果的代码并没有使用 CIFilter,而是调用了 vImageBoxConvolve_ARGB8888,这是 vImage 高性能图像处理框架 的一部分。

    这种技术在 WWDC 2013 视频 Implementing Engaging UI on iOS 中有详细介绍。


    我知道问题是关于 iOS 7 的,但现在在 iOS 8 中,可以使用 UIBlurEffect 为任何 UIView 对象添加模糊效果:

    UIVisualEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];    
    effectView.frame = imageView.bounds;
    [imageView addSubview:effectView];
    

    我收到一个警告:“未使用的变量Image”,它是代码倒数第二行。 - user2891448
    1
    @user2891448 我不确定你想要对image做什么。也许更新imageView.image = image; - Rob
    最后一件事,我想用一个变量来设置模糊程度的值,我该怎么做?这是在[gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey];中。 - user2891448
    2
    假设你有一个名为radiusCGFloat变量,那么你可以这样写:[gaussianBlurFilter setValue:@(radius) forKey:kCIInputRadiusKey]; - Rob
    我知道我说过最后一次是最后一次,但当我按下按钮时,一切都完美地运作。唯一的问题是图像会缩小(我知道它实际上是扩大了),但我需要实现什么来使其看起来与之前相同大小?这是否与CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]]有关? - user2891448
    显示剩余7条评论

    4

    对我来说,这个方法很有效,但是它很慢。我将在应用程序加载时进行转换,并在许多位置使用一次转换后的图像。

    这个模糊效果适用于iOS 8.4。使用Swift语言。

    override func viewDidLoad()
    {
        super.viewDidLoad()
    
        var backgroundImage = self.blurImage(UIImage(named: "background.jpg")!)
    
        self.view.backgroundColor = UIColor(patternImage:backgroundImage)
    }
    
    func blurImage(imageToBlur:UIImage) -> UIImage
    {
        var gaussianBlurFilter = CIFilter(name: "CIGaussianBlur")
        gaussianBlurFilter.setValue(CIImage(CGImage: imageToBlur.CGImage), forKey:kCIInputImageKey)
    
        var inputImage = CIImage(CGImage: imageToBlur.CGImage)
    
        var outputImage = gaussianBlurFilter.outputImage
        var context = CIContext(options: nil)
        var cgimg = context.createCGImage(outputImage, fromRect: inputImage.extent())
    
        return UIImage(CGImage: cgimg)!
    }
    

    1
    非常有趣,但速度也非常慢... :/ 至少在Apple TV上是这样。 - marco.marinangeli
    是的,它很慢 :/。你可以使用“按需”模糊处理来解决这个问题,或者如果你有一些应用内加载,那么调用blurImage函数。在某个时候,我保存了模糊图像,所以当我需要它们时,我可以从内存或其他地方加载它们,而不是再次调用该函数。希望这可以帮助你或指引你朝着正确的方向 :)))。 - MB_iOSDeveloper

    1

    Swift 4 UIImage 扩展,不需要强制解包:

    extension UIImage {
        /// Applies a gaussian blur to the image.
        ///
        /// - Parameter radius: Blur radius.
        /// - Returns: A blurred image.
        func blur(radius: CGFloat = 6.0) -> UIImage? {
            let context = CIContext()
            guard let inputImage = CIImage(image: self) else { return nil }
    
            guard let clampFilter = CIFilter(name: "CIAffineClamp") else { return nil }
            clampFilter.setDefaults()
            clampFilter.setValue(inputImage, forKey: kCIInputImageKey)
    
            guard let blurFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
            blurFilter.setDefaults()
            blurFilter.setValue(clampFilter.outputImage, forKey: kCIInputImageKey)
            blurFilter.setValue(radius, forKey: kCIInputRadiusKey)
    
            guard let blurredImage = blurFilter.value(forKey: kCIOutputImageKey) as? CIImage,
                let cgImage = context.createCGImage(blurredImage, from: inputImage.extent) else { return nil }
    
            let resultImage = UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
            return resultImage
        }
    }
    

    我强烈建议在后台线程上模糊图像:
    let image = UIImage(named: "myImage")
    DispatchQueue.global(qos: .userInitiated).async {
        let blurredImage = image.blur()
        DispatchQueue.main.async {
            self.myImageView.image = blurredImage
        }
    }
    

    图片在这样做后被裁剪了,有没有办法可以避免这种情况? - Roman Samoilenko

    1
    CIFilter的输入需要是CIImage而不是UIImage

    0

    Swift 2.0

    创建一个UIImageView的扩展。(文件-新建文件-空白Swift文件-命名为Extensions。)

    import Foundation
    import UIKit
    
    extension UIImageView{
    
     //Method 1
     func makeBlurImage(targetImageView:UIImageView?)
     {
      let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
      let blurEffectView = UIVisualEffectView(effect: blurEffect)
      blurEffectView.frame = targetImageView!.bounds
    
      blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] // for supporting device rotation
      targetImageView?.addSubview(blurEffectView)
     }
     //Method 2
     func convertToBlurImage(imageToBlur:UIImage) -> UIImage
     {
      let gaussianBlurFilter = CIFilter(name: "CIGaussianBlur")
      gaussianBlurFilter!.setValue(CIImage(CGImage: imageToBlur.CGImage!), forKey:kCIInputImageKey)
    
      let initialImage = CIImage(CGImage: imageToBlur.CGImage!)
    
      let finalImage = gaussianBlurFilter!.outputImage
      let finalImagecontext = CIContext(options: nil)
    
      let finalCGImage = finalImagecontext.createCGImage(finalImage!, fromRect: initialImage.extent)
      return UIImage(CGImage: finalCGImage)
     }
    }
    

    使用方法:

    方法一:

    override func viewDidLoad() {
      super.viewDidLoad()
    
      let sampleImageView = UIImageView(frame: CGRectMake(0, 200, 300, 325))
      let sampleImage:UIImage = UIImage(named: "ic_120x120")!
      sampleImageView.image =  sampleImage
    
      //Convert To Blur Image Here
      sampleImageView.makeBlurImage(sampleImageView)
    
      self.view.addSubview(sampleImageView)
     }
    

    使用方法2:

       override func viewDidLoad() {
          super.viewDidLoad()
    
          let sampleImageView = UIImageView(frame: CGRectMake(0, 200, 300, 325))
          let sampleImage:UIImage = UIImage(named: "ic_120x120")!
    
          //Convert to Blurred Image Here
          let sampleImage2 =  sampleImageView.convertToBlurImage(sampleImage)
          sampleImageView.image =  sampleImage2
    
          self.view.addSubview(sampleImageView)
         }
    

    0
    这是一个关于图像模糊的扩展程序 Swift 3
    extension UIImage {
    
        public func blurImage(radius: CGFloat) -> UIImage {
    
            let inputImage = CIImage(image: self)!
    
            let parameters: [String:Any] = [
                kCIInputRadiusKey: radius,
                kCIInputImageKey: inputImage
            ]
            let filter = CIFilter(name: "CIGaussianBlur",
                                  withInputParameters: parameters)!
    
            let cgimg = CIContext().createCGImage(filter.outputImage!, from: inputImage.extent)
            return UIImage(cgImage: cgimg!)
        }
    
    }
    

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