版本記錄
| 版本號 | 時間 |
|---|---|
| V1.0 | 2021.10.08 星期五 |
前言
Core Image是IOS5中新加入的一個框架,里面提供了強大高效的圖像處理功能,用來對基于像素的圖像進行操作與分析。還提供了很多強大的濾鏡,可以實現你想要的效果,下面我們就一起解析一下這個框架。感興趣的可以參考上面幾篇。
1. Core Image框架詳細解析(一) —— 基本概覽
2. Core Image框架詳細解析(二) —— Core Image濾波器參考
3. Core Image框架詳細解析(三) —— 關于Core Image
4. Core Image框架詳細解析(四) —— Processing Images處理圖像(一)
5. Core Image框架詳細解析(五) —— Processing Images處理圖像(二)
6. Core Image框架詳細解析(六) —— 圖像中的面部識別Detecting Faces in an Image(一)
7. Core Image框架詳細解析(七) —— 自動增強圖像 Auto Enhancing Images
8. Core Image框架詳細解析(八) —— 查詢系統中的過濾器 Querying the System for Filters
9. Core Image框架詳細解析(九) —— 子類化CIFilter:自定義效果的配方 Subclassing CIFilter: Recipes for Custom Effects(一)
10. Core Image框架詳細解析(十) —— 子類化CIFilter:自定義效果的配方 Subclassing CIFilter: Recipes for Custom Effects(二)
11. Core Image框架詳細解析(十一) —— 獲得最佳性能 Getting the Best Performance
12. Core Image框架詳細解析(十二) —— 使用反饋處理圖像 Using Feedback to Process Images
13. Core Image框架詳細解析(十三) —— 在寫一個自定義濾波器之前你需要知道什么?
14. Core Image框架詳細解析(十四) —— 創(chuàng)建自定義濾波器 Creating Custom Filters(一)
15. Core Image框架詳細解析(十五) —— 創(chuàng)建自定義濾波器 Creating Custom Filters(二)
16. Core Image框架詳細解析(十六) —— 包裝和加載圖像單元 Packaging and Loading Image Units
17. Core Image框架詳細解析(十七) —— 一個簡單說明和示例(一)
開始
首先看下主要內容:
學習使用
Metal Shading Language創(chuàng)建您自己的Core Image過濾器,以構建提供像素級圖像處理的內核。內容來自翻譯。
接著看下寫作環(huán)境:
Swift 5, iOS 14, Xcode 12
下面就是原文了。
Core Image 是一個強大而高效的圖像處理框架。 您可以使用框架提供的內置過濾器創(chuàng)建漂亮的效果,也可以創(chuàng)建自定義過濾器和圖像處理器。 您可以調整顏色、幾何形狀并執(zhí)行復雜的卷積。
制作漂亮的濾鏡是一門藝術,最偉大的藝術家之一是列奧納多·達·芬奇 (Leonardo da Vinci)。 在本教程中,您將為達芬奇的名畫添加一些有趣的元素。
在此過程中,您將:
- 了解
Core Image的類和內置過濾器。 - 使用內置過濾器創(chuàng)建過濾器。
- 使用自定義顏色內核
(color kernel)轉換圖像的顏色。 - 使用自定義扭曲內核轉換圖像的幾何形狀。
- 學習調試
Core Image問題。
注意:由于 Apple問題,本教程不適用于
Xcode 13和iOS 15。您現在必須使用Xcode 12。
準備好你的畫筆,哎呀,我的意思是你的 Xcode 準備好了。 是時候潛入 Core Image 的奇妙世界了!
打開下載項目。 在 starter 中打開 RayVinci 項目。 構建并運行。

您將看到達芬奇最著名的四部作品。點擊一幅畫會打開一個sheet,但圖像的輸出是空的。
在本教程中,您將為這些圖像創(chuàng)建過濾器,然后查看在輸出中應用過濾器的結果。
向下滑動以關閉sheet。接下來,點擊右上角的Filter List。
該按鈕應顯示可用內置過濾器的列表。但是等等,它目前是空的。你接下來會解決這個問題。
Introducing Core Image Classes
在填充過濾器列表之前,您需要了解 Core Image 框架的基本類。
-
CIImage:表示準備好進行處理或由
Core Image過濾器生成的圖像。CIImage對象包含圖像的所有數據,但實際上不是圖像。這就像一個食譜,它包含了做一道菜的所有成分,但不是這道菜本身。
您將在本教程后面看到如何渲染要顯示的圖像。
CIFilter:獲取一張或多張圖像,通過應用轉換來處理每張圖像,并生成一個
CIImage作為其輸出。您可以鏈接多個過濾器并創(chuàng)建有趣的效果。CIFilters的對象是可變的,不是線程安全的。CIContext:渲染過濾器的處理結果。例如,
CIContext幫助從CIImage對象創(chuàng)建Quartz 2D圖像。
要了解有關這些類的更多信息,請參閱Core Image Tutorial: Getting Started。
現在您已經熟悉了 Core Image 類,是時候填充過濾器列表了。
Fetching the List of Built-In Filters
打開 RayVinci 并選擇 FilterListView.swift。 將 FilterListView 中的 filterList 替換為:
let filterList = CIFilter.filterNames(inCategory: nil)
在這里,您通過使用 filterNames(inCategory:) 并傳遞 nil 作為類別來獲取 Core Image 提供的所有可用內置過濾器的列表。 您可以在 CIFilter 的開發(fā)人員文檔developer documentation中查看可用類別列表。
打開 FilterDetailView.swift。 將正文中的Text("Filter Details")替換為:
// 1
if let ciFilter = CIFilter(name: filter) {
// 2
ScrollView {
Text(ciFilter.attributes.description)
}
} else {
// 3
Text("Unknown filter!")
}
在這里,你:
- 1) 使用過濾器名稱初始化過濾器
ciFilter。 由于名稱是一個字符串并且可能拼寫錯誤,因此初始化程序返回一個可選的。 因此,您需要檢查過濾器是否存在。 - 2) 您可以使用屬性檢查過濾器的各種屬性。 在這里,如果過濾器存在,您將創(chuàng)建一個
ScrollView并在文本視圖中填充屬性的描述。 - 3) 如果過濾器不存在或未知,您將顯示一個
Text視圖來解釋情況。
構建并運行。 點擊Filter List。 哇,過濾器太多了!
點按任何過濾器以查看其屬性。

很了不起,不是嗎?你才剛剛開始!在下一節(jié)中,您將使用這些內置過濾器來使對“蒙娜麗莎”的陽光下熠熠生輝。
Using Built-In Filters
現在,你已經看到可用過濾器列表中,您將使用這些來創(chuàng)建一個有趣的效果。
打開ImageProcessor.swift。在頂部,在類聲明之前,添加:
enum ProcessEffect {
case builtIn
case colorKernel
case warpKernel
case blendKernel
}
在這里,您將 ProcessEffect 聲明為enum。 它包含您將在本教程中使用的所有過濾器案例。
將以下內容添加到 ImageProcessor:
// 1
private func applyBuiltInEffect(input: CIImage) {
// 2
let noir = CIFilter(
name: "CIPhotoEffectNoir",
parameters: ["inputImage": input]
)?.outputImage
// 3
let sunGenerate = CIFilter(
name: "CISunbeamsGenerator",
parameters: [
"inputStriationStrength": 1,
"inputSunRadius": 300,
"inputCenter": CIVector(
x: input.extent.width - input.extent.width / 5,
y: input.extent.height - input.extent.height / 10)
])?
.outputImage
// 4
let compositeImage = input.applyingFilter(
"CIBlendWithMask",
parameters: [
kCIInputBackgroundImageKey: noir as Any,
kCIInputMaskImageKey: sunGenerate as Any
])
}
在這里,你:
- 1) 聲明一個將
CIImage作為輸入并應用內置過濾器的私有方法。 - 2) 您首先使用
CIPhotoEffectNoir創(chuàng)建一個變暗、喜怒無常的黑色效果。CIFilter以一個字符串作為名稱和字典形式的參數。您從outputImage獲取生成的過濾圖像。 - 3) 接下來,您使用
CISunbeamsGenerator創(chuàng)建一個生成器過濾器。這將創(chuàng)建一個陽光遮罩。在參數中,您設置:-
inputStriationStrength:表示陽光的強度。 -
inputSunRadius:代表太陽的半徑。 -
inputCenter:陽光中心的 x 和 y 位置。在這種情況下,您將位置設置在圖像的右上角。
-
- 4) 在這里,您使用
CIBlendWithMask創(chuàng)建風格化效果。您可以通過將CIPhotoEffectNoir的結果設置為背景圖像并將sunGenerate設置為蒙版圖像來對輸入input應用過濾器。這種組合的結果是一個CIImage。
ImageProcessor 有輸出output,一個發(fā)布的屬性,它是一個 UIImage。您需要將合成結果轉換為 UIImage 以顯示它。
在 ImageProcessor 中,在@Published var output = UIImage()下面添加以下內容:
let context = CIContext()
在這里,您創(chuàng)建了一個所有過濾器都將使用的 CIContext 實例。
將以下內容添加到 ImageProcessor:
private func renderAsUIImage(_ image: CIImage) -> UIImage? {
if let cgImage = context.createCGImage(image, from: image.extent) {
return UIImage(cgImage: cgImage)
}
return nil
}
在這里,您使用上下文從 CIImage 創(chuàng)建一個 CGImage 實例。
然后使用 cgImage 創(chuàng)建一個 UIImage。 用戶將看到此圖像。
1. Displaying a Built-In Filter’s Output
將以下內容添加到 applyBuiltInEffect(input:) 的末尾:
if let outputImage = renderAsUIImage(compositeImage) {
output = outputImage
}
這將使用 renderAsUIImage(_:) 將compositeImage(CIImage)轉換為 UIImage。 然后將結果保存到輸出output。
將以下新方法添加到 ImageProcessor:
// 1
func process(painting: Painting, effect: ProcessEffect) {
// 2
guard
let paintImage = UIImage(named: painting.image),
let input = CIImage(image: paintImage)
else {
print("Invalid input image")
return
}
switch effect {
// 3
case .builtIn:
applyBuiltInEffect(input: input)
default:
print("Unsupported effect")
}
}
在這里,你:
- 1) 創(chuàng)建一個方法作為
ImageProcessor的入口點。 它需要一個Painting和一個effect實例來應用。 - 2) 檢查有效圖像。
- 3) 如果效果是
.builtIn類型,則調用applyBuiltInEffect(input:)來應用過濾器。
打開 PaintWall.swift。 在 Button 的 action 閉包中 selectedPainting = Painting[index] 下方,添加:
var effect = ProcessEffect.builtIn
if let painting = selectedPainting {
switch index {
case 0:
effect = .builtIn
default:
effect = .builtIn
}
ImageProcessor.shared.process(painting: painting, effect: effect)
}
在這里,您將第一幅畫的effect設置為 .builtIn。 您還將其設置為默認效果。 然后通過在 ImageProcessor 上調用 process(painting:, effect:) 來應用過濾器。
構建并運行。 點擊“Mona Lisa”。 您將看到在輸出中應用了一個內置過濾器!

讓蒙娜麗莎陽光普照的偉大工作。難怪她在笑!現在是使用 CIKernel 創(chuàng)建過濾器的時候了。
Meet CIKernel
使用 CIKernel,您可以放置自定義代碼,稱為內核(kernel),以逐個像素地操作圖像。 GPU 處理這些像素。您使用 Metal Shading Language 編寫內核,與較舊的 Core Image Kernel Language(自 iOS 12 起已棄用)相比,它具有以下優(yōu)勢:
- 支持
Core Image內核的所有強大功能,如連接和平鋪。 - 在構建時預編譯,帶有錯誤診斷。這樣,您無需等待運行時出現錯誤。
- 提供語法高亮和語法檢查。
有不同類型的內核:
- CIColorKernel:改變像素的顏色但不知道像素的位置。
- CIWarpKernel:改變像素的位置但不知道像素的顏色。
- CIBlendKernel:以優(yōu)化的方式混合兩個圖像。
要創(chuàng)建和應用內核,您需要:
- 1) 首先,向項目添加自定義構建規(guī)則。
- 2) 然后,添加
Metal源文件。 - 3) 加載內核。
- 4) 最后,初始化并應用內核。

接下來,您將實施這些步驟中的每一個。 準備好享受有趣的旅程吧!
Creating Build Rules
您需要編譯 Core Image Metal 代碼并將其與特殊標志鏈接。

在項目導航器中選擇 RayVinci target。 然后,選擇Build Rules選項卡。 單擊 + 添加新的構建規(guī)則。
然后,設置第一個新的構建規(guī)則:
- 1) 將
Process設置為Source files with name matching:。 然后將*.ci.metal設置為值。 - 2) 取消選中
Run once per architecture。 - 3) 添加以下腳本:
xcrun metal -c -I $MTL_HEADER_SEARCH_PATHS -fcikernel "${INPUT_FILE_PATH}" \
-o "${SCRIPT_OUTPUT_FILE_0}"
這會使用所需的 -fcikernel 標志調用 Metal 編譯器。
- 4) 在輸出文件
Output Files中添加以下內容
$(DERIVED_FILE_DIR)/${INPUT_FILE_BASE}.air
這會產生一個以 .ci.air 結尾的輸出二進制文件。

接下來,再次單擊 + 添加另一個新的構建規(guī)則。
對于第二個新構建規(guī)則,請按照以下步驟操作:
- 1) 將
Process設置為Source files with name matching:。 然后將*.ci.air設置為值。 - 2) 取消選中
Run once per architecture。 - 3) 添加以下腳本:
xcrun metallib -cikernel "${INPUT_FILE_PATH}" -o "${SCRIPT_OUTPUT_FILE_0}"
這將使用所需的 -cikernel 標志調用 Metal 鏈接器。
- 4) 在輸出文件
Output Files中添加以下內容:
$(METAL_LIBRARY_OUTPUT_DIR)/$(INPUT_FILE_BASE).metallib
這會在應用程序包中生成一個以 .ci.metallib 結尾的文件。

接下來,是時候添加 Metal 源了。
Adding the Metal Source
首先,您將為顏色內核創(chuàng)建一個源文件。 在項目導航器中,突出顯示 RayVinci 項目正下方的 RayVinci。
右鍵單擊并選擇New Group。 將此新組命名為 Filters。 然后,突出顯示該組并添加一個名為 ColorFilterKernel.ci.metal 的新 Metal 文件。
打開文件并添加:
// 1
#include <CoreImage/CoreImage.h>
// 2
extern "C" {
namespace coreimage {
// 3
float4 colorFilterKernel(sample_t s) {
// 4
float4 swappedColor;
swappedColor.r = s.g;
swappedColor.g = s.b;
swappedColor.b = s.r;
swappedColor.a = s.a;
return swappedColor;
}
}
}
下面是代碼分解:
- 1) 包含
Core Image的header可讓您訪問框架提供的類。 這會自動包含Core Image Metal內核庫CIKernelMetalLib.h。 - 2) 內核需要位于
extern "C"閉包內,以便在運行時可以通過名稱訪問它。 接下來,指定coreimage的命名空間。 您在coreimage命名空間中聲明所有擴展以避免與Metal發(fā)生沖突。 - 3) 在這里,您聲明
colorFilterKernel,它接受類型為sample_t的輸入。sample_t表示來自輸入圖像的單個顏色樣本。colorFilterKernel返回一個表示像素的RGBA值的float4。 - 4) 然后,您聲明一個新的
float4、swappedColor,并交換來自輸入樣本的RGBA值。 然后返回具有交換值的樣本。
接下來,您將編寫代碼來加載和應用內核。
Loading the Kernel Code
要加載和應用內核,首先要創(chuàng)建 CIFilter 的子類。
在過濾器Filters組中創(chuàng)建一個新的 Swift 文件。 將其命名為 ColorFilter.swift 并添加:
// 1
import CoreImage
class ColorFilter: CIFilter {
// 2
var inputImage: CIImage?
// 3
static var kernel: CIKernel = { () -> CIColorKernel in
guard let url = Bundle.main.url(
forResource: "ColorFilterKernel.ci",
withExtension: "metallib"),
let data = try? Data(contentsOf: url) else {
fatalError("Unable to load metallib")
}
guard let kernel = try? CIColorKernel(
functionName: "colorFilterKernel",
fromMetalLibraryData: data) else {
fatalError("Unable to create color kernel")
}
return kernel
}()
// 4
override var outputImage: CIImage? {
guard let inputImage = inputImage else { return nil }
return ColorFilter.kernel.apply(
extent: inputImage.extent,
roiCallback: { _, rect in
return rect
},
arguments: [inputImage])
}
}
在這里,你:
- 1) 首先導入
Core Image框架。 - 2) 子類化
CIFilter包括兩個主要步驟:- 指定輸入參數。在這里,您使用
inputImage。 - 重寫
outputImage。
- 指定輸入參數。在這里,您使用
- 3) 然后,您聲明一個靜態(tài)屬性
kernel,它加載ColorFilterKernel.ci.metallib的內容。這樣,庫只加載一次。然后使用ColorFilterKernel.ci.metallib的內容創(chuàng)建CIColorKernel的實例。 - 4) 接下來,您
override outputImage。在這里,您通過使用apply(extent:roiCallback:arguments:)來應用內核。extent決定了有多少輸入圖像被傳遞到內核。
您傳遞了整個圖像,因此過濾器將應用于整個圖像。 roiCallback 確定在 outputImage 中渲染矩形所需的輸入圖像的矩形。在這里, inputImage 和 outputImage 的 rect 沒有改變,所以你返回相同的值并將參數數組中的 inputImage 傳遞給內核。
現在您已經創(chuàng)建了顏色內核過濾器,您將把它應用到圖像上。
Applying the Color Kernel Filter
打開 ImageProcessor.swift。將以下方法添加到 ImageProcessor:
private func applyColorKernel(input: CIImage) {
let filter = ColorFilter()
filter.inputImage = input
if let outputImage = filter.outputImage,
let renderImage = renderAsUIImage(outputImage) {
output = renderImage
}
}
在這里,您聲明 applyColorKernel(input:)。 這需要一個 CIImage 作為輸入。 您可以通過創(chuàng)建 ColorFilter 的實例來創(chuàng)建自定義過濾器。
過濾器的 outputImage 應用了顏色內核。 然后使用 renderAsUIImage(_:) 創(chuàng)建 UIImage 實例并將其設置為輸出。
接下來,在 process(painting:effect:) 中處理 .colorKernel,如下所示。 在default之上添加這個新case:
case .colorKernel:
applyColorKernel(input: input)
在這里,您調用 applyColorKernel(input:) 來應用您的自定義顏色內核過濾器。
最后,打開 PaintingWall.swift。 在 Button 的 action 閉包中 case 0 正下方的 switch 語句中添加以下內容:
case 1:
effect = .colorKernel
這將第二幅畫的效果設置為 .colorKernel。
構建并運行。 現在點擊第二幅畫“The Last Supper”。 您將看到應用的顏色內核過濾器和圖像中交換的 RGBA 值。

很好! 接下來,您將對達芬奇的神秘Salvator Mundi創(chuàng)建酷炫的扭曲效果。
Creating a Warp Kernel
與顏色內核類似,您將從添加 Metal 源文件開始。 在過濾器Filters組中創(chuàng)建一個名為 WarpFilterKernel.ci.metal 的新 Metal 文件。 打開文件并添加:
#include <CoreImage/CoreImage.h>
//1
extern "C" {
namespace coreimage {
//2
float2 warpFilter(destination dest) {
float y = dest.coord().y + tan(dest.coord().y / 10) * 20;
float x = dest.coord().x + tan(dest.coord().x/ 10) * 20;
return float2(x,y);
}
}
}
這是您添加的內容:
- 1) 就像在顏色內核
Metal源中一樣,您包含Core Image header并將該方法包含在extern "C"括號中。 然后指定coreimage命名空間。 - 2) 接下來,您使用
destination類型的輸入參數聲明warpFilter(_:),允許訪問您當前正在計算的像素的位置。 它返回輸入圖像坐標中的位置,然后您可以將其用作源。
您可以使用 coord() 訪問目標像素的 x 和 y 坐標。 然后,您應用簡單的數學運算來轉換坐標并將它們作為源像素坐標返回,以創(chuàng)建有趣的平鋪效果。
注意:嘗試在
warpFilter(_:)中用sin替換tan,你會得到一個有趣的失真效果!
Loading the Warp Kernel
與您為顏色內核創(chuàng)建的過濾器類似,您將創(chuàng)建一個自定義過濾器來加載和初始化扭曲內核。
在過濾器Filters組中創(chuàng)建一個新的 Swift 文件。 將其命名為 WarpFilter.swift 并添加:
import CoreImage
// 1
class WarpFilter: CIFilter {
var inputImage: CIImage?
// 2
static var kernel: CIWarpKernel = { () -> CIWarpKernel in
guard let url = Bundle.main.url(
forResource: "WarpFilterKernel.ci",
withExtension: "metallib"),
let data = try? Data(contentsOf: url) else {
fatalError("Unable to load metallib")
}
guard let kernel = try? CIWarpKernel(
functionName: "warpFilter",
fromMetalLibraryData: data) else {
fatalError("Unable to create warp kernel")
}
return kernel
}()
// 3
override var outputImage: CIImage? {
guard let inputImage = inputImage else { return .none }
return WarpFilter.kernel.apply(
extent: inputImage.extent,
roiCallback: { _, rect in
return rect
},
image: inputImage,
arguments: [])
}
}
在這里,你:
- 1) 創(chuàng)建
WarpFilter作為CIFilter的子類,以inputImage作為輸入參數。 - 2) 接下來,您聲明靜態(tài)屬性
kernel以加載WarpFilterKernel.ci.metallib的內容。 然后使用.metallib的內容創(chuàng)建CIWarpKernel的實例。 - 3) 最后,您通過重寫
outputImage來提供輸出。 在override中,您使用apply(extent:roiCallback:arguments:)將內核應用于inputImage并返回結果。
Applying the Warp Kernel Filter
打開 ImageProcessor.swift。 將以下內容添加到 ImageProcessor:
private func applyWarpKernel(input: CIImage) {
let filter = WarpFilter()
filter.inputImage = input
if let outputImage = filter.outputImage,
let renderImage = renderAsUIImage(outputImage) {
output = renderImage
}
}
在這里,您聲明 applyColorKernel(input:),它將 CIImage 作為輸入。 然后創(chuàng)建一個 WarpFilter 實例并設置 inputImage。
過濾器的 outputImage 應用了扭曲內核。 然后使用 renderAsUIImage(_:) 創(chuàng)建 UIImage 實例并將其保存到輸出。
接下來,在 process(painting:effect:) 中添加以下 case,在 case .colorKernel 下:
case .warpKernel:
applyWarpKernel(input: input)
在這里,您處理 .warpKernel 的case并調用 applyWarpKernel(input:)來應用扭曲內核過濾器。
最后,打開 PaintingWall.swift。 在action中 case 1正下方的 switch 語句中添加以下 case:
case 2:
effect = .warpKernel
這將第三幅畫的效果設置為 .warpKernel。
構建并運行。 點擊 Salvator Mundi 的畫作。 你會看到一個有趣的基于扭曲的瓷磚效果應用。

恭喜! 您將自己的風格應用于杰作!
1. Challenge: Implementing a Blend Kernel
CIBlendKernel 針對混合兩個圖像進行了優(yōu)化。 作為一個有趣的挑戰(zhàn),為 CIBlendKernel 實現一個自定義過濾器。 一些提示:
- 1) 創(chuàng)建一個
CIFilter的子類,它接收兩個圖像:輸入圖像和背景圖像。 - 2) 使用內置的可用
CIBlendKernel內核。 對于此挑戰(zhàn),請使用built-in multiply混合內核。 - 3) 在
ImageProcessor中創(chuàng)建一個方法,將混合內核過濾器應用于圖像并將結果設置為輸出。 您可以使用項目資產中提供的multi_color圖片作為濾鏡的背景圖片。 另外,處理.blendKernel的case。 - 4) 將此過濾器應用于
PaintWall.swift中的第四張圖像。
您將在下載的材料中找到在最終項目中實施的解決方案。 祝你好運!
Debugging Core Image Issues
了解 Core Image 如何渲染圖像可以幫助您在圖像未按預期顯示時進行調試。 最簡單的方法是在調試時使用 Core Image Quick Look。
1. Using Core Image Quick Look
打開 ImageProcessor.swift。 在 applyColorKernel(input:)中設置output的行上放置一個斷點。 構建并運行。 點擊“The Last Supper”。

當您遇到斷點時,將鼠標懸停在 outputImage 上。 你會看到一個顯示地址的小彈出框。
單擊眼睛符號。 將出現一個窗口,顯示制作圖像的圖形。 很酷吧?
2. Using CI_PRINT_TREE
CI_PRINT_TREE 是基于與 Core Image Quick Look 相同的基礎架構的調試功能。 它有多種模式和操作。
選擇并編輯 RayVinci 的scheme。 選擇 Run 選項卡并添加 CI_PRINT_TREE 作為值為 7 pdf 的新環(huán)境變量。

CI_PRINT_TREE 的值采用 graph_type output_type 選項的形式。
graph_type 表示Core Image渲染的階段。 以下是您可以指定的值:
-
1:顯示顏色空間的初始圖形。 -
2:一個優(yōu)化的圖表,顯示了Core Image是如何優(yōu)化的。 -
4:顯示您需要多少內存的連接圖。 -
7:詳細日志記錄。 這將打印所有上述圖表。
對于 output_type,您可以指定 PDF 或 PNG。 它將文檔保存到一個臨時目錄。
構建并運行。 在模擬器中選擇“The Last Supper”。 現在,通過使用終端導航到 /tmp 來打開 Mac 上的臨時目錄。
您將看到所有圖形為 PDF 文件。 打開以 _initial_graph.pdf 作為后綴的文件之一。

輸入在底部,輸出在頂部。 紅色節(jié)點代表顏色內核(color kernels),而綠色節(jié)點代表扭曲內核(warp kernels)。 您還將看到每個步驟的ROI和范圍。
要了解有關可以為 CI_PRINT_TREE 設置的各種選項的更多信息,請查看此 WWDC 會議:Discover Core Image debugging techniques。
在本教程中,您學習了使用基于 Metal 的 Core Image 內核創(chuàng)建和應用自定義過濾器。 要了解更多信息,請查看這些 WWDC 視頻:
- Advances in Core Image: Filters, Metal, Vision and More
- Build Metal-based Core Image kernels with Xcode
您還可以參考 Apple 的指南,Metal Shading Language for Core Image Kernels。
后記
本篇主要講述了使用
Metal Shading Language創(chuàng)建你自己的Core Image濾波器進行像素級圖像處理,感興趣的給個贊或者關注~~~~
