Core Image-简单的图片滤镜实现

来源:互联网 发布:html 代码生成软件 编辑:程序博客网 时间:2024/06/06 05:03
CoreImage 是一种图片处理和分析的技术用于对静态和视频图片进行高效的处理。是一个OS X和iOS的图像处理框架,Core Image很强大,不仅可以做图片处理,还可以做人脸识别等多种工作。它有两个基本概念:滤镜和滤镜图表。一个滤镜是一个对象,有很多输入和输出,并执行一些变换。例如,模糊滤镜可能需要输入图像和一个模糊半径来产生适当的模糊后的输出图像。一个滤镜图表是一个链接在一起的滤镜网络,使得一个滤镜的输出可以是另一个滤镜的输入。以这种方式,可以实现精心制作的效果。

常用的几个类
 
CIContext

图像上下文,用来渲染CIImage,将作用在CIImage上的滤镜链应用到原始的图片数据中。CIContext可以是基于CPU的,也可以是基于GPU的,这两种渲染的区别是:使用CPU渲染的iOS会采用GCD来对图像进行渲染,这保证了CPU渲染在大部分情况下更可靠,比CPU渲染更容易使用,可以在后台实现渲染过程;而GPU渲染方式使用OpenGL ES2.0来渲染图像,这种方式CPU完全没有负担,应用程序的运行循环不会受到图像渲染的影响,而且渲染比CPU渲染更快但是GPU渲染无法在后台运行。

对于复杂的图像滤镜使用GPU更好,但是如果在处理视频并保存文件,或保存照片到照片库中时为避免程序退出对图片保存造成影响,这时应该使用CPU进行渲染。默认情况是用CPU渲染的。

GPU受限于硬件纹理尺寸,如果你的程序在后台继续处理和保存图片的话,需要使用CPU,因为当app切换到后台状态时GPU处理会被打断。基于GPU的CIContext对象无法跨应用访问。比如你打开UIImagePickerController要选张照片进行美化,如果你直接在UIImagePickerControllerDelegate的委托方法里调用CIContext对象进行处理,那么系统会自动将其降为基于CPU的,速度会变慢,所以正确的方法应该是在委托方法里先把照片保存下来,回到主类里再来处理。

CIFilter

图像处理滤镜,每种滤镜有不同的参数设置。用来表示CoreImage提供的各种滤镜。滤镜使用键-值来设置输入值,一旦这些值设置好,CIFilter就可以用来生成新的CIImage输出图像了。这里的输出的图像不会进行实际的图像渲染,他只包含一个对输入图像的引用以及需要应用与数据上的滤镜链。iOS永远在最佳的时间选择渲染图像。

CIImage

Core Image 框架中的图像类型, 主要用于输入和输出图像。是CoreImage框架中最基本代表图像的对象,它不仅包含元图像数据,还包含作用在原图像上的滤镜链。在CIImage被CIContext渲染出来之前,它是依赖于滤镜链的,滤镜是不会更改CIImage中的图像数据。参考开发者文档CIImage。

在使用滤镜之前我们可以先了解一下平台主要支持哪些滤镜,以及这些滤镜的方法和参数如何设置,可以使用下面的方法进行打印查看:
   //查看所有内置滤镜    func showAllFilters(){         let filterNames = CIFilter.filterNames(inCategory: kCICategoryBuiltIn)         for filterName in filterNames{             let filter = CIFilter(name: filterName)             print("\rfilter:\(filterName),\rattributes:\(filter!.attributes)")        }    }

在 iOS中打印会发现有 127 中滤镜,这些滤镜基本使用方法是类似的,只是参数设置有所区别。可以看这里,里面有每种滤镜的详细介绍和图片使用效果。

使用Core Image框架创建滤镜效果一般分为以下几步:

1:创建图像上下文 CIContext
2:创建滤镜 CIFilter
3:创建过滤原图片 CIImage
4:调用 CIFilter 的 setValue: forKey:方法为滤镜指定源图片
5:设置滤镜参数【可选】
6:取得输出图片显示或保存

具体Demo实例,原文地址这里。

Demo主要是实现从相册库获取图片,然后可以通过slider的滑动对图片进行滤镜,并且可以对滤镜之后的图片进行保存。Demo中也提供了部分滤镜类型的选择,并进行相应的滤镜操作,基本的Demo功能和效果如下GIF图。




具体代码如下,代码部分有对应的注释解析:

import CoreImage  //是Apple一个非常强大的框架,它只处理一件事情,对图片进行滤镜控制。import UIKitclass ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {@IBOutlet weak var imageView: UIImageView!@IBOutlet weak var intensity: UISlider!var currentImage: UIImage! //存储用户选中的图片    //CIContext:是Core Image的组成部分,主要用于处理渲染var context: CIContext!    //CIFilter:是Core Image filter,用于存储我们当前使用的滤镜方式var currentFilter: CIFilter!override func viewDidLoad() {super.viewDidLoad()title = "YACIFP"        //添加系统+号按钮navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(importPicture))        //创建默认的Core Image渲染上下文和滤镜效果context = CIContext()currentFilter = CIFilter(name: "CISepiaTone")}        //改变滤镜效果,使用actionSheet进行选择@IBAction func changeFilter(_ sender: AnyObject) {let ac = UIAlertController(title: "Choose filter", message: nil, preferredStyle: .actionSheet)ac.addAction(UIAlertAction(title: "CIBumpDistortion", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CIGaussianBlur", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CIPixellate", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CISepiaTone", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CITwirlDistortion", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CIUnsharpMask", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "CIVignette", style: .default, handler: setFilter))ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))present(ac, animated: true)}    //保存图片到相册库@IBAction func save(_ sender: AnyObject) {UIImageWriteToSavedPhotosAlbum(imageView.image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)}    //slider滑动事件,通过滑动改变slider当前值进而改变对当前图片的滤镜效果@IBAction func intensityChanged(_ sender: AnyObject) {applyProcessing()}    //添加图片func importPicture() {        //这里需要注意,访问图片库需要进行请求,所以plist文件需要添加对应的描述文本。key为Privacy - Photo Library Usage Description” value随意,这里使用We need to import photoslet picker = UIImagePickerController()picker.allowsEditing = truepicker.delegate = selfpresent(picker, animated: true)}   //实现协议方法func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {        //判断图片是否存在guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }        //去除图片库界面dismiss(animated: true)        //存储选中的图片即原始图片,当用户进行一次滤镜之并保存之后,需要原始图片进行下次滤镜操作currentImage = image        //得到CIImagelet beginImage = CIImage(image: currentImage)currentFilter.setValue(beginImage, forKey: kCIInputImageKey)        //应用滤镜applyProcessing()}func applyProcessing() {        //返回当前滤镜类型所支持的所有input key值let inputKeys = currentFilter.inputKeys        //根据输入的key值进行设置对应的值,对于key值需要注意,每一种不同类型的滤镜方式有可能包含如下key值,有可能不包含,所有需要进行判断,不然会出现奔溃。比如:kCIInputIntensityKey,如果我们使用CIBumpDistortion类型,它是不包含kCIInputIntensityKey值的。对于更多的值可以看官方文档if inputKeys.contains(kCIInputIntensityKey) { currentFilter.setValue(intensity.value, forKey: kCIInputIntensityKey) }if inputKeys.contains(kCIInputRadiusKey) { currentFilter.setValue(intensity.value * 200, forKey: kCIInputRadiusKey) }if inputKeys.contains(kCIInputScaleKey) { currentFilter.setValue(intensity.value * 10, forKey: kCIInputScaleKey) }if inputKeys.contains(kCIInputCenterKey) { currentFilter.setValue(CIVector(x: currentImage.size.width / 2, y: currentImage.size.height / 2), forKey: kCIInputCenterKey) }        //这里需要两个参数,第一个是渲染的图片,第二个是渲染图片的区域if let cgimg = context.createCGImage(currentFilter.outputImage!, from: currentFilter.outputImage!.extent) {            //将CGImage转换为UIImage并显示渲染之后的图片let processedImage = UIImage(cgImage: cgimg)self.imageView.image = processedImage}}    //选择对应的滤镜方式func setFilter(action: UIAlertAction!) {guard currentImage != nil else { return }        //更新当前滤镜currentFiltercurrentFilter = CIFilter(name: action.title!)        //并使用原始图作为滤镜初始图并应用滤镜效果let beginImage = CIImage(image: currentImage)currentFilter.setValue(beginImage, forKey: kCIInputImageKey)        applyProcessing()}    //保持图片的action事件,保存成功和失败进行相应的提示func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {if let error = error {let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)ac.addAction(UIAlertAction(title: "OK", style: .default))present(ac, animated: true)} else {let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)ac.addAction(UIAlertAction(title: "OK", style: .default))present(ac, animated: true)}}}

参考:

iOS图像处理之Core Image

Core Image 的使用(iOS 的图像处理)
APPCODA基本使用教程

0 0
原创粉丝点击