Core Image 例如,可以让您修改过滤器的图像处理图像。它提供各种效果的功能、图像处理或显示。 !
您可以将每个过滤器的图像显示器链接,每一个过滤器的图像显示器以图像或帧显示。过滤器成一个并显示组合视频。与通过过滤器处理它的图像图像非常有效,一次。
在本教程中,您将获得使用 Core Image 的实践经验。您将应用一些不同的过滤图像,并实时了解对应用炫耀效果是多么容易。
入门
在开始之前,先看看 Core Image 框架中的一些最重要的类:
-
CI时间。完成核心
CIContext
图像的所有处理。这有点Core Graphics或OpenGL的时间。 -
图像。此类保存图像数据。一个
UIImage
,一个图像文件或数据可以创建它。 -
过滤器包含许多过滤器。它的过滤器有一些特定的过滤器属性。
CIFilter
过滤器、各种过滤器、各种不同的示例。
您将在此项目中使用这些类中的每一个。
CoreImageFun
单击本教程顶部或底部的下载材料按钮以下载入门项目。打开CoreImageFun.xcodeproj并运行它。这是一个简单的应用程序,一个带有图像和滑块的单一屏幕。滑块还没有做任何事情,但我们将使用它来展示CIFilter
的力量。您还会注意到屏幕右上角的相机按钮。您将在本教程后面使用它来调出图像选择器。

图像过滤基础
您将首先通过 a 运行图像CIFilter
并将其显示在屏幕上。每次要将 a 应用CIFilter
到图像时,都需要做四件事:
-
创建一个 CIImage 对象。A
CIImage
有几种初始化方法。在本教程中,您将CIImage(image:)
使用CIImage
从UIImage
. 浏览文档以了解更多创建CIImage
. -
创建一个 CIContext。A
CIContext
可以是基于 CPU 或 GPU 的。ACIContext
的初始化成本很高,因此您可以重用它而不是一遍又一遍地创建它。输出CIImage
对象时总是需要一个。 - 创建一个 CIFilter。创建过滤器时,您会在其上配置一些属性,这些属性取决于您使用的过滤器。
-
获取过滤器输出。过滤器为您提供输出图像作为
CIImage
. 您可以UIImage
使用将其转换为 aCIContext
,如下所示。
应用过滤器
在理论信息之后,是时候看看它是如何工作的了。将以下代码添加到ViewController.swift:
func applySepiaFilter ( intensity : Float ) {
// 1个
守卫 let uiImage = UIImage (named: "image" ) else { return }
let ciImage = CIImage (image: uiImage)
// 2
guard let filter = CIFilter (name: "CISepiaTone" ) else { return }
// 3
filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(强度,forKey:kCIInputIntensityKey)
// 4
guard let outputImage = filter.outputImage else { return }
// 5
let newImage = UIImage (ciImage: outputImage)
imageView.image = newImage
}
这是代码的作用。它:
- 创建 a
UIImage
并使用它来创建CIImage
. - 创建一个
CIFilter
类型CISepiaTone
。这是棕褐色调的类型。 - 过滤器采用
CISepiaTone
两个值。首先,输入图像:kCIInputImageKey
,它是一个CIImage
实例。其次,一个强度:kCIInputIntensityKey
,一个float
介于 0 和 1 之间的值。如果没有任何值,大多数过滤器都使用它们的默认值。一个例外是CIImage
. 这必须提供一个值,因为没有默认值。 -
CIImage
使用该属性从过滤器中取出outputImage
。 - 将
CIImage
背面转为 aUIImage
并将其显示在图像视图中。
接下来,通过添加以下内容来调用添加的新方法viewDidLoad()
:
应用棕褐色过滤器(强度:0.5)
这会触发强度值为 0.5 的图像过滤。在本教程的后面部分,您将使用滑块来尝试各种强度值。
构建并运行项目。您将看到您的图像被棕褐色调过滤器过滤:

恭喜,您已经使用CIImage
并且CIFilter
很好!:]
把它放到上下文中
在继续之前,您应该了解一项优化。
如上所述,您需要 aCIContext
来应用CIFilter
. 但是在上面的例子中没有提到这个对象。事实证明,UIImage(CIImage:)
它为您完成了所有工作。它创建一个CIContext
并使用它来过滤图像。这使得 Core Image API 很容易使用。
有一个主要缺点:CIContext
每次使用它都会创建一个新的。CIContext
实例应该是可重用的以提高性能。如果要使用滑块更新过滤器值,则CIContext
每次更改过滤器时都必须创建一个新的。这种方法会很慢。
首先,将以下属性添加到ViewController
:
让时间= CIContext (选项:无)
CIContext
接受选项字典。它指定诸如颜色格式或上下文是否应该在 CPU 或 GPU 上运行等选项。对于这个应用程序,默认值很好,所以你传入nil
那个参数。
接下来,删除步骤 5applySepiaFilter(intensity:)
并将其替换为以下内容:
守卫让 cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
imageView.image = UIImage (cgImage: cgImage)
在这里,您使用CIContext
绘制 aCGImage
并使用它来创建UIImage
在图像视图中显示的 a。
工作并运行。确保它像以前一样。

在此示例中,CIContext
自己处理创建并没有太大区别。您将了解为什么这样做对性能很重要,因为您在下一节中设置了更改过滤器的能力。
更改过滤器值
这很棒,但这只是你可以使用 Core Image 过滤器做的事情的开始。是时候使用图像下方那个漂亮的滑块来改变滤镜效果了。
您已经为CIContext
实例添加了一个属性。现在,您将添加一个属性来保存过滤器。
已经有一个IBAction
连接到滑块的Value Changed操作。它被称为sliderValueChanged(_:)
。在此方法中,您将在滑块值更改时重做图像过滤器。但是你不想重做整个过程。那将是非常低效的,并且会花费太长时间。您需要更改类中的一些内容,因此您需要保留您在 中创建的一些对象applySepiaFilter(intensity:)
。
context
在声明的正下方添加以下属性:
让过滤器= CIFilter(名称:“CISepiaTone”)!
接下来,viewDidLoad()
在调用之前添加以下内容applySepiaFilter(intensity:)
:
guard let uiImage = UIImage (named: "image" ) else { return }
let ciImage = CIImage (image: uiImage)
filter.setValue(ciImage, forKey: kCIInputImageKey)
在这里,您将图像设置为过滤。你以前在applySepiaFilter(intensity:)
. 但最好将其移动到viewDidLoad()
以防止对每个滑块值更改的调用。
您将一些代码移至viewDidLoad()
,因此替换applySepiaFilter(intensity:)
为以下内容:
func applySepiaFilter (强度: Float ) {
filter.setValue(强度,forKey:kCIInputIntensityKey)
守卫 让outputImage = filter.outputImage else { return }
守卫 让cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
imageView.image = UIImage (cgImage: cgImage)
}
最后,将以下内容添加到sliderValueChanged(_:)
:
applySepiaFilter(强度:slider.value)
当滑块值发生变化时,applySepiaFilter(intensity:)
将以新的强度值运行。
您的滑块设置为默认值:最小 0,最大 1,默认 0.5。多么方便!这些恰好是 this 的正确值CIFilter
。
构建并运行。您应该有一个功能正常的实时滑块,可以实时更改图像的棕褐色值。

从相册中获取照片
现在您可以立即更改过滤器的值,事情变得有趣了!但是,如果您不喜欢这种花的形象怎么办?接下来,您将设置一个UIImagePickerController
以从相册中获取图片并进入您的应用程序,以便您可以使用它们。
已经有一个IBAction
连接到相机按钮的Touch Up Inside动作。它被称为loadPhoto()
。将以下代码添加到loadPhoto()
:
让选择器= UIImagePickerController ()
picker.delegate = self
present(picker, animated: true )
第一行代码实例化一个新的UIImagePickerController
. 将图像选择器的代理设置为self
( ViewController
),然后呈现选择器。
这里有一个编译器错误。您需要声明ViewController
符合UIImagePickerControllerDelegate
和UINavigationControllerDelegate
协议。
将以下扩展添加到ViewController.swift的底部:
扩展 ViewController : UIImagePickerControllerDelegate , UINavigationControllerDelegate {
func imagePickerController (
_picker : UIImagePickerController ,
didFinishPickingMediaWithInfo info : [ UIImagePickerController . InfoKey : Any ]) {
}
}
此委托方法返回所选图像以及info
字典中的一些相关信息。有关此字典中各种数据的更多详细信息,请查看文档。
构建并运行该应用程序,然后点击按钮,该按钮将显示图片选择器,其中包含您相册中的照片。

选择图像什么都不做。你即将改变这一点。将以下代码添加到imagePickerController(_:didFinishPickingMediaWithInfo:)
:
//1
守卫 let selectedImage = info[.originalImage] as? UIImage 其他{返回}
//2
let ciImage = CIImage (image: selectedImage)
filter.setValue(ciImage, forKey: kCIInputImageKey)
//3
applySepiaFilter(强度:slider.value)
//4
解雇(动画:真)
这是代码分解。它:
- 使用键检索选择图像
originalImage
UIImagePickerController.InfoKey
。 - 将所选图像应用到滤镜。
-
applySepiaFilter(intensity:)
使用强度的当前滑块值调用。这将更新图像视图。 - 完成对选定图像的过滤后关闭图像选择器。
构建并运行。现在,您将能够更新相册中的任何图像。

图像元数据呢?
当然,是时候谈谈图像元数据了。在手机上拍摄的图像文件具有与之相关的各种数据,例如 GPS 坐标、图像格式和方向。
特别是方向是您需要保留的东西。将 a加载UIImage
到 aCIImage
中,渲染到 aCGImage
并转换回 aUIImage
会从图像中去除元数据。为了保持方向,您需要记录它,然后将其传回UIImage
.
首先向ViewController.swift添加一个新属性:
var方向= UIImage。方向向上
imagePickerController(_:didFinishPickingMediaWithInfo:)
接下来,在调用之前添加以下行applySepiaFilter(intensity:)
:
方向= selectedImage.imageOrientation
这会将选定的图像方向保存到属性中。
最后,更改对象中applySepiaFilter(intensity:)
set 中的行imageView
:
imageView.image = UIImage(cgImage:cgImage,比例:1,方向:方向)
现在,如果您以非默认方向拍摄照片,应用程序会保留它。
还有哪些其他过滤器可用?
最大的优势之一CIFilter
是链接过滤器的能力。为此,您将创建一个专用方法来处理CIImage
并过滤它,使其看起来像一张旧照片。
该
CIFilter
API 在 macOS 上有 160 多个过滤器,其中大部分在 iOS 上也可用。现在也可以创建自定义过滤器。要查看任何可用的过滤器或属性,请查看文档。
创建旧照片滤镜
将以下方法添加到ViewController
:
func applyOldPhotoFilter (强度: Float ) {
// 1
filter.setValue(强度,forKey:kCIInputIntensityKey)
// 2
让随时= CIFilter(名称: “ CIRandomGenerator ”)
// 3
let lighten = CIFilter (name: "CIColorControls" )
减轻?.setValue(随机? .outputImage,forKey:kCIInputImageKey)
减轻?.setValue( 1 -强度,forKey: kCIInputBrightnessKey)
减轻?.setValue( 0 , forKey: kCIInputSaturationKey)
// 4
guard let ciImage = filter.value(forKey: kCIInputImageKey) as? CIImage else { return }
让croppedImage = lighten ?.输出图像?.cropped(到:ciImage.extent)
// 5
let composition = CIFilter (name: "CIHardLightBlendMode" )
复合材料?.setValue(filter.outputImage, forKey: kCIInputImageKey)
复合材料?.setValue(croppedImage, forKey: kCIInputBackgroundImageKey)
// 6
let vignette = CIFilter (name: "CIVignette" )
小插图?.setValue(复合? .outputImage,forKey:kCIInputImageKey)
小插图?.setValue(强度* 2 , forKey: kCIInputIntensityKey)
小插图?.setValue(强度* 30 , forKey: kCIInputRadiusKey)
// 7
守卫 让outputImage = vignette ? .outputImage else { return }
守卫 让cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
imageView.image = UIImage(cgImage:cgImage,比例:1,方向:方向)
}
这是正在发生的事情,逐节进行。编码:
-
在您之前使用的棕褐色调滤镜中设置强度。
-
建立一个过滤器,创建一个如下所示的随机噪声模式: 它不采用任何参数。您将使用此噪点模式为最终的“旧照片”外观添加纹理。
-
改变随机噪声发生器的输出。您想将其更改为灰度并使其变亮一点,因此效果不那么引人注目。输入图像键设置为随机过滤器的 outputImage 属性。这是一种将一个过滤器的输出作为下一个过滤器的输入传递的便捷方式。
-
已
cropped(to:)
获取输出CIImage
并将其裁剪为提供的矩形。在这种情况下,您需要裁剪CIRandomGenerator
过滤器的输出,因为它会一直持续下去。如果您在某些时候不裁剪它,则会收到错误消息,指出过滤器具有“无限范围”。CIImage
s 实际上并不包含图像数据;他们描述了创建它的“配方”。直到您调用CIContext
处理数据的方法。 -
结合棕褐色和
CIRandomGenerator
过滤器的输出。后者执行与 Adobe Photoshop 图层中的“强光”设置相同的操作。Photoshop 中的大多数(如果不是全部)滤镜选项都可以使用 Core Image 实现。 -
在此合成输出上运行晕影滤镜,使照片的边缘变暗。您可以使用强度值来设置此效果的半径和强度。
-
获取输出图像并将其设置为图像视图。
应用旧照片滤镜
这就是这个过滤器链的全部内容。您现在已经了解这些过滤器链可能变得多么复杂。您可以将 Core Image 滤镜组合到这些类型的链中,这样您就可以实现无穷无尽的各种效果。
如果您想查看所有这些操作,请将所有调用替换applySepiaFilter(intensity:)
为applyOldPhotoFilter(intensity:)
。
构建并运行。您应该获得更精致的旧照片效果,包括棕褐色、少许噪点和一些暗角。

亲爱的读者,这种噪音可能会更微妙,但如何完善取决于您。现在,您可以使用 Core Image 的全部功能。
本教程的最终项目资料下载地址
链接:https://pan.baidu.com/share/init?surl=ZTx8tmHhsd0vNojdtc9vmQ
提取码:ijn1
这里也推荐一些面试相关的内容,祝各位网友都能拿到满意offer!
GCD面试要点
block面试要点
Runtime面试要点
RunLoop面试要点
内存管理面试要点
MVC、MVVM面试要点
网络性能优化面试要点
网络编程面试要点
KVC&KVO面试要点
数据存储面试要点
混编技术面试要点
设计模式面试要点
UI面试要点
网友评论