Swift3.1动画之Core Image

作者: Dwyane_Coding | 来源:发表于2017-04-13 01:36 被阅读307次
    图片来源于网络

    前言:Core Image是一个强大的框架,可让您轻松地将过滤器应用于图像。您可以获得各种各样的效果,如修改活力,色调或曝光。它可以使用CPU或GPU来处理图像数据,并且速度非常快 - 足以实现视频帧的实时处理!
    核心图像滤镜也可以链接在一起,以一次将多个效果应用于图像或视频帧。多个滤波器被组合成应用于图像的单个滤波器。与通过每个过滤器一次处理图像相比,这样做非常有效。

    入门

    在开始之前,让我们来讨论Core Image框架中的一些最重要的类:
    CIContext。核心图像的所有处理都以CIContext完成。这与Core Graphics或OpenGL上下文有些相似。
    CIImage。该类保存图像数据。它可以从UIImage,从图像文件或从像素数据创建。
    CIFilter。CIFilter类有一个字典,用于定义它所代表的特定过滤器的属性。过滤器的例子是振动,颜色反转,裁剪等等。

    基本图像过滤

    通过简单地运行您的图像CIFilter并在屏幕上显示图像来开始。每次想要将CIFilter应用于图像时,有4个步骤:

    1、创建一个CIImage对象。CIImage有几种初始化方法,包括:CIImage(CIImage(contentsOf: ),CIImage(data :),CIImage(CGImage :),CIImage(bitmapData:bytesPerRow:size:format:colorSpace :)等几个。最常用的是用CIImage(contentsOf: )
    2、创建CIContext。CIContext可以是基于CPU或GPU的。CIContext初始化相对耗费资源,因此您可以重用它,而不是一遍又一遍地创建它。输出CIImage对象时,您将始终需要一个。
    3、创建一个CIFilter。创建过滤器时,您可以配置依赖于您使用的过滤器的许多属性。
    4、获取过滤器输出。过滤器为您提供输出图像作为CIImage - 您可以使用CIContext将其转换为UIImage,如下所示

      // 1
      let fileURL = Bundle.main.url(forResource: "beauty", withExtension: "jpg")
      // 2
      let beginImage = CIImage(contentsOf: fileURL!)
      // 3
      let filter = CIFilter (name: "CISepiaTone")
      filter?.setValue(beginImage, forKey: kCIInputImageKey)
      filter?.setValue(0.5, forKey: kCIInputIntensityKey)
      // 4
      let newImage = UIImage(ciImage: (filter?.outputImage)!)
      self.imageView.image = newImage;
    

    我们先来看看这一节:

    1、此行创建一个<code>NSURL</code>对象,该对象保存图像文件的路径。
    2、接下来,使用<code>CIImage(contentsOf: )</code>构造函数创建您的CIImage。
    3、接下来,您将创建您的<code>CIFilter</code>对象。<code>CIFilter</code>构造函数使用过滤器的名称,并指定该过滤器的键和值的字典。每个过滤器将有自己唯一的密钥和一组有效的值。所述<code>CISepiaTone</code>过滤器只需两个值:<code>KCIInputImageKey</code>(一个CIImage)和在0和1之间的<code>kCIInputIntensityKey</code> ,你给该值0.5。大多数过滤器具有默认值,如果没有提供值,将使用该值。一个例外是<code>CIImage</code>,这是必须提供的,因为没有默认。
    4、将<code>CIImage</code>从过滤器中恢复与使用该<code>outputImage</code>属性一样简单。一旦输出<code>CIImage</code>,您将需要将其转换为<code>UIImage</code>。该<code>UIImage(ciImage:)</code>构造函数转换了<code>CIImage</code>到<code>UIImage</code>。一旦将其转换为<code>UIImage</code>,您只需将其显示在您之前添加的<code>imageView</code>中。

    运行该项目,您将看到由深褐色滤镜过滤的图像。

    置于上下文

    在您继续了解之前,您应该了解一个优化。
    我之前提到你需要一个CIContext应用CIFilter,但在上面的例子中没有提到这个对象。事实证明,<code>UIImage(ciImage:)code</code>构造函数为您做所有的工作。它创建CIContext并使用它来执行过滤图像的工作。这使得使用Core Image API非常简单。
    有一个主要的缺点 - CIContext每次使用时都会创建一个新的。CIContext实例旨在可重用以提高性能。如果要使用滑块来更新过滤器值,就像在本教程中所做的那样,每次更改过滤器时都会创建一个新的CIContext将太慢了。
    我们这样做是正确的。从viewDidLoad()添加的代码中删除步骤4 ,并将其替换为以下内容:

    // 1
    let context = CIContext(options:nil)
    
    // 2
    let cgimg = context.createCGImage(filter!.outputImage!, from: filter!.outputImage!.extent)
    
    // 3
    let newImage = UIImage(cgImage: cgimg!)
    self.imageView.image = newImage;
    

    再次,我们一起来看看这一节。
    在这里,您设置CIContext对象并使用它来绘制CGImage。该CIContext(options:)构造采用指定的选项一个NSDictionary如色彩格式,或上下文是否应在CPU或GPU上运行。对于这个应用程序,默认值是好的,所以你传递为nil为该参数。
    <code>createCGImage(outputImage:from:)</code>使用提供的CIImage在上下文中调用将返回一个新的CGImage实例。
    接下来,您使用<code>UIImage(cgImage:)</code>构造函数从新创建的CGImage创建UIImage,而不是像以前一样直接从CIImage创建。注意,在完成它之后,不需要明确地释放CGImage,就像在Objective-C中一样。在Swift中,ARC可以自动释放Core Foundation对象。
    构建和运行,并确保它像以前一样工作。
    在这个例子中,自己处理CIContext的创建并没有太多的区别。但在下一节中,您将看到为什么这对于性能很重要,因为您实现了动态修改过滤器的功能!
    更改过滤器值

    下面增加滑块,每次滑块更改时,都需要使用不同的值重做图像过滤器。但是,您不想重做整个过程,这将是非常低效的,并且需要太长时间。您将需要更改类中的一些内容,以便您可以保留在viewDidLoad方法中创建的一些对象。
    如果为了重新使用CIContext,而每次重新创建它程序将运行非常缓慢。
    添加一些实例变量才能完成此任务。将以下三个属性添加到ViewController类中:

    var context: CIContext!
    var filter: CIFilter!
    var beginImage: CIImage!
    

    更改代码,因此<code>viewDidLoad()</code>使用这些属性,而不是声明新的局部变量,如下所示:

    beginImage = CIImage(contentsOf: fileURL!)
    
    filter = CIFilter (name: "CISepiaTone")
    filter?.setValue(beginImage, forKey: kCIInputImageKey)
    filter?.setValue(0.5, forKey: kCIInputIntensityKey)
    
    let outputImage = filter.outputImage
    context = CIContext(options:nil)
    
    let cgimg = context.createCGImage(filter!.outputImage!, from: filter!.outputImage!.extent)
    

    实现changeValue方法。在CIFilter字典中改变<code>inputIntensity</code>值。
    一旦你改变了这个值,你需要重复几个步骤:

    1、从CIFilter获取输出CIImage。
    2、将CIImage转换为CGImage。
    3、将CGImage转换为UIImage,并将其显示在图像视图中。

    将创建一个方法<code>amountSliderValueChanged(sender :)</code>:

    @IBAction func amountSliderValueChange(_ sender: UISlider) {
        let sliderValue = sender.value
        
        filter.setValue(sliderValue, forKey: kCIInputIntensityKey)
        let outputImage = filter.outputImage
        
        let cgimg = context.createCGImage(outputImage!, from: outputImage!.extent)
        
        let newImage = UIImage(cgImage: cgimg!)
        self.imageView.image = newImage
    }
    
    Core Image变化

    老相片效果

    在这个Demo中,会得到一个更精致的老照片效果,完成与棕褐色,一点噪音和一些晕影

    func oldPhoto (img: CIImage, withAmount intensity: Float) -> CIImage {
        //1 CISepiaTone 棕褐色调
        let sepia = CIFilter(name: "CISepiaTone")
        sepia?.setValue(img, forKey: kCIInputImageKey)
        sepia?.setValue(intensity, forKey: "inputIntensity")
        
        //2 设置一个过滤器,创建一个随机噪声模式
        let random = CIFilter(name: "CIRandomGenerator")
        
        //3 改变随机噪声发生器的输出
        let lighten = CIFilter(name:"CIColorControls")
        lighten?.setValue(random?.outputImage, forKey:kCIInputImageKey)
        lighten?.setValue(1 - intensity, forKey:"inputBrightness")
        lighten?.setValue(0, forKey:"inputSaturation")
        
        //4 cropping(to rect: CGRect)输出CIImage并将其作用到所提供的rect
        let croppedImage = lighten?.outputImage?.cropping(to: beginImage.extent)
        
        //5 将棕褐色滤镜的输出与CIRandomGenerator滤镜的输出相结合。
        let composite = CIFilter(name:"CIHardLightBlendMode")
        composite?.setValue(sepia?.outputImage, forKey:kCIInputImageKey)
        composite?.setValue(croppedImage, forKey:kCIInputBackgroundImageKey)
        
        //6 合成输出上运行晕影滤镜(vignette filter),使照片的边缘变暗
        let vignette = CIFilter(name:"CIVignette")
        vignette?.setValue(composite?.outputImage, forKey:kCIInputImageKey)
        vignette?.setValue(intensity * 2, forKey:"inputIntensity")
        vignette?.setValue(intensity * 30, forKey:"inputRadius")
        
        //7 返回滤镜的输出
        return vignette!.outputImage!
    }
    
    

    效果图:

    老照片.png

    解析以上代码:
    1、像在简单的场景中所做的一样,设置棕褐色滤镜。您在方法中传入浮点值以设置深色效果的强度。该值将由滑块提供。
    2、设置一个过滤器,创建一个如下所示的随机噪声模式:


    CIRandomGenerator

    它不需要任何参数。您将使用这种噪音模式将纹理添加到最终的“旧照片”外观。
    3、改变随机噪声发生器的输出。你想把它改成灰度,并减轻一点点,所以效果不那么戏剧化。您会注意到,输入图像键被设置为随机过滤器的outputImage属性。这是一个方便的方式来传递一个过滤器的输出作为下一个的输入。
    4、 cropping(to rect: CGRect)输出CIImage并将其作用到所提供的rect。在这种情况下,您需要裁剪CIRandomGenerator过滤器的输出,因为它无限制地打砖块。如果您在某些时候没有裁剪,就会出现一个错误,表示过滤器具有“无限长度”。CIImages实际上并不包含图像数据,它们描述了创建它的“配方”。直到你在CIContext上调用一个方法来实际处理数据。
    5、将棕褐色滤镜的输出与CIRandomGenerator滤镜的输出相结合。该过滤器执行与Photoshop图层中的“硬光”设置完全相同的操作。使用Core Image可以实现Photoshop中的大多数滤镜选项。
    6、在此合成输出上运行晕影滤镜,使照片的边缘变暗。您正在使用滑块的值来设置此效果的半径和强度。
    7、返回最后一个过滤器的输出。

    相关文章

      网友评论

        本文标题:Swift3.1动画之Core Image

        本文链接:https://www.haomeiwen.com/subject/bobvattx.html