iOS圖形處理概論:OpenGL ES,Metal,Core Graphics,Core Image,GPUImage,Scene Kit (3D) ,Sprite Kit (2D),OpenCV

原文鏈接:https://www.jianshu.com/p/24d691ae0720

前言

對於剛接觸iOS圖形相關框架的小白,有一些圖形框架在字面上和功能上非常容易混淆。這裏旨在總結一下各種框架,區分它們的概念和功能,以作日後進一步細分學習的指引。因而,本文並不會針對具體框架作詳解,只作區分引導,讀者可自行選擇方向繼續深造。爲此,筆者總結了一張各種框架關係圖,如下所示:

iOS圖形處理相關概念集合

總的來說,iOS與圖形圖像處理相關的框架都在這裏了:

    1. 界面圖形框架 -- UIKit
    1. 核心動畫框架 -- Core Animation
    1. 蘋果封裝的圖形框架 -- Core Graphics & Quartz 2D
    1. 傳統跨平臺圖形框架 -- OpenGL ES
    1. 蘋果最新力推的圖形框架 -- Metal
    1. 適合圖片的蘋果濾鏡框架 -- Core Image
    1. 適合視頻的第三方濾鏡方案 -- GPUImage
    1. 遊戲引擎 -- Scene Kit (3D) 和 Sprite Kit (2D)
    1. 計算機視覺在iOS的應用 -- OpenCV for iOS

1. 界面圖形框架 -- UIKit

UIKit

UIKit是一組Objective-C API,爲線條圖形、Quartz圖像和顏色操作提供Objective-C 封裝,並提供2D繪製、圖像處理及用戶接口級別的動畫。

UIKit包括UIBezierPath(繪製線、角度、橢圓及其它圖形)、UIImage(顯示圖像)、UIColor(顏色操作)、UIFont和UIScreen(提供字體和屏幕信息)等類以及在位圖圖形環境、PDF圖形環境上進行繪製和 操作的功能等, 也提供對標準視圖的支持,也提供對打印功能的支持。

UIKit與Core Graphics的關係

在UIKit中,UIView類本身在繪製時自動創建一個圖形環境,即Core Graphics層的CGContext類型,作爲當前的圖形繪製環境。在繪製時可以調用 UIGraphicsGetCurrentContext 函數獲得當前的圖形環境,例如:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    NSLog(@"%s",__func__);
    //1.獲取上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    //2.描述路徑
    UIBezierPath * path = [UIBezierPath bezierPath];
    //起點
    [path moveToPoint:CGPointMake(10, 10)];
    //終點
    [path addLineToPoint:CGPointMake(100, 100)];
    //設置顏色
    [[UIColor whiteColor]setStroke];
    //3.添加路徑
    CGContextAddPath(contextRef, path.CGPath);
    //顯示路徑
    CGContextStrokePath(contextRef);
    
}

這段代碼就是在UIView的子類中調用 UIGraphicsGetCurrentContext 函數獲得當前的圖形環境,然後向該圖形環境添加路徑,最後繪製。

2. 核心動畫框架 -- Core Animation

Core Animation

Core Animation 是一套Objective-C API,實現了一個高性能的複合引擎,並提供一個簡單易用的編程接口,給用戶UI添加平滑運動和動態反饋能力。

Core Animation 是 UIKit 實現動畫和變換的基礎,也負責視圖的複合功能。使用Core Animation可以實現定製動畫和細粒度的動畫控制,創建複雜的、支持動畫和變換的layered 2D視圖。

Core Animation 不屬於繪製系統,但它是以硬件複合和操作顯示內容的基礎設施。這個基礎設施的核心是layer對象,用來管理和操作顯示內容。在 iOS 中 每一個視圖都對應Core Animation的一個層對象,與視圖一樣,層之間也組織爲層關係樹。一個層捕獲視圖內容爲一個被圖像硬件容易操作的位圖。在多數應用中層作爲管理視圖的方式使用,但也可以創建獨立的層到一個層關係樹中來顯示視圖不夠支持的顯示內容。

OpenGL ES的內容也可以與Core Animation內容進行集成。

爲了使用Core Animation實現動畫,可以修改 層的屬性值 來觸發一個action對象的執行,不同的action對象實現不同的動畫。

Core Animatio相關基類及子類

Core Animation 提供了一下一組應用可以採用的類來提供對不同動畫類型的支持:

  • CAAnimation 是一個抽象公共基類,CAAnimation採用CAMediaTiming 和CAAction協議爲動畫提供時間(如週期、速度、重複次數等)和action行爲(啓動、停止等)。
  • CAPropertyAnimation 是 CAAnimation的抽象子類,爲動畫提供一個由一個key路徑規定的層屬性的支持;
  • CABasicAnimation 是CAPropertyAnimation的具體子類,爲一個層屬性提供簡單插入能力。
  • CAKeyframeAnimation 也是CAPropertyAnimation的具體子類,提供key幀動畫支持。

3. 蘋果封裝的圖形框架 -- Core Graphics & Quartz 2D

Core Graphics

Core Graphics是一套C-based API, 支持向量圖形,線、形狀、圖案、路徑、剃度、位圖圖像和pdf 內容的繪製。

Quartz 2D

Quartz 2D是Core Graphics中的2D 繪製呈現引擎。Quartz是資源和設備無關的,提供路徑繪製,anti-aliased呈現,剃度填充圖案,圖像,透明繪製和透明層、遮蔽和陰影、顏色管理,座標轉換,字體、offscreen呈現、pdf文檔創建、顯示和分析等功能。

Quartz 2D能夠與所有的圖形和動畫技術(如Core Animation, OpenGL ES, 和 UIKit 等)一起使用。

Quartz 2D採用paint模式進行繪製。

圖形環境Context

Quartz 2D中使用的圖形環境也由一個類CGContext表示。

在Quartz 2D中可以把一個圖形環境作爲一個繪製目標。當使用Quartz 2D進行繪製時,所有設備特定的特性被包含在你使用的特定類型的圖形環境中,因此通過給相同的圖像操作函數提供不同的圖像環境你就能夠畫相同的圖像到不同的設備上,因此做到了圖像繪製的設備無關性。

圖形環境Context是個比較抽象的東西,它不僅僅是一個可以繪製的圖層,還包含爲當前圖層設置的參數,如陰影,線條粗細,繪製模式等。可以類比成一個新建的Photoshop圖層以及當前筆觸,顏色等配置。

對於移動平臺,有三種常見的圖形環境Context:

  • 位圖上下文(A bitmap graphics context):一般用於繪製圖片或者自定義控件。

    • View Graphics Context: 由UIView自動創建,你重寫UIView drawRect方法時,你的內容會畫在這個上下文上。
    • Bitmap Graphics Context: 繪製在該上下文的內容會以點陣形式存儲在一塊內存中。簡單說,就是爲圖片開闢一塊內存,然後在裏面畫東西,上下文幫你把圖片內存抽象成一個Context(圖層)了。
  • PDF上下文(A PDF graphics context):用於生成pdf文件。

  • 圖層上下文(A layer context):用於離屏繪製( offscreen drawing)。

Quartz 2D提供的主要類包括:

  • CGContext:表示一個圖形環境;
  • CGPath:使用向量圖形來創建路徑,並能夠填充和stroke;
  • CGImage:用來表示位圖;
  • CGLayer:用來表示一個能夠用於重複繪製和offscreen繪製的繪製層;
  • CGPattern:用來表示Pattern,用於重複繪製;
  • CGShading和 CGGradient:用於繪製剃度;
  • CGColor 和 CGColorSpace;用來進行顏色和顏色空間管理;
  • CGFont, 用於繪製文本;
  • CGPDFContentStream、CGPDFScanner、CGPDFPage、CGPDFObject,CGPDFStream, CGPDFString等用來進行pdf文件的創建、解析和顯示。

4. 傳統跨平臺圖形框架 -- OpenGL ES

OpenGL ES

OpenGL ES是一套多功能開放標準的用於嵌入系統的C-based的圖形庫,用於2D和3D數據的可視化。OpenGL被設計用來轉換一組圖形調用功能到底層圖形硬件(GPU),由GPU執行圖形命令,用來實現複雜的圖形操作和運算,從而能夠高性能、高幀率利用GPU提供的2D和3D繪製能力。

OpenGL ES規範本身不定義繪製表面和繪製窗口,因此ios爲了使用它必須提供和創建一個OpenGL ES 的呈現環境,創建和配置存儲繪製命令結果的framebuffer 及創建和配置一個或多個呈現目標。

EAGL

在 iOS中使用EAGL提供的EAGLContext類 來實現和提供一個呈現環境,用來保持OpenGL ES使用到的硬件狀態。 EAGL是一個Objective-C API,提供使OpenGL ES與Core Animation和UIKIT集成的接口。

在調用任何OpenGL ES 功能之前必須首先初始化一個EAGLContext 對象。每一個IOS應用的每一個線程都有一個當前context,在調用OpenGL ES函數時,使用或改變此context中的狀態。

EAGLContext 的類方法setCurrentContext: 用來設置當前線程的當前context。EAGLContext 的類方法currentContext 返回當前線程的當前context。在切換相同線程的兩個上下文之前,必須調用glFlush函數來確保先前已提交的命令被提交到圖形硬件中。

GLKit

可以採用不同的方式使用OpenGL ES以便呈現OpenGL ES內容到不同的目標:GLKit和CAEAGLLayer。

爲了創建全屏幕的視圖或使OpenGL ES內容與UIKit視圖集成,可以使用GLKit。在使用GLKit時,GLKit提供的類GLKView類本身實現呈現目標及創建和維護一個framebuffer。

GLKit是一組Objective-C 類,爲使用OpenGL ES 提供一個面向對象接口,用來簡化OpenGL ES應用的開發。

CAEAGLLayer

爲了使OpenGL ES內容作爲一個Core Animation層的部分內容時,可以使用CAEAGLLayer 作爲呈現目標,並需要另外創建framebuffer以及自己實現和控制整個繪製流程。

GLKit支持四個3D應用開發的關鍵領域:

1) GLKView 和GLKViewController類提供一個標準的OpenGL ES視圖和相關聯的呈現循環。GLKView可以作爲OpenGL ES內容的呈現目標,GLKViewController提供內容呈現的控制和動畫。視圖管理和維護一個framebuffer,應用只需在framebuffer進行繪畫即可。

2)GLKTextureLoader 爲應用提供從IOS支持的各種圖像格式的源自動加載紋理圖像到OpenGL ES 圖像環境的方式,並能夠進行適當的轉換,並支持同步和異步加載方式。

3)數學運算庫,提供向量、矩陣、四元數的實現和矩陣堆棧操作等OpenGL ES 1.1功能。

4)Effect效果類提供標準的公共着色效果的實現。能夠配置效果和相關的頂點數據,然後創建和加載適當的着色器。GLKit 包括三個可配置着色效果類:GLKBaseEffect實現OpenGL ES 1.1規範中的關鍵的燈光和材料模式, GLKSkyboxEffect提供一個skybox效果的實現, GLKReflectionMapEffect 在GLKBaseEffect基礎上包括反射映射支持。

5. 蘋果最新力推的圖形框架 -- Metal

Metal框架支持GPU硬件加速、高級3D圖形渲染以及大數據並行運算。且提供了先進而精簡的API來確保框架的細粒度(fine-grain),並且在組織架構、程序處理、圖形呈現、運算指令以及指令相關數據資源的管理上都支持底層控制。其核心目的是儘可能的減少CPU開銷,而將運行時產生的大部分負載交由GPU承擔

編寫基於底層圖形 API 的渲染引擎時,除了 Metal 以外的其他選擇還有 OpenGL 和 OpenGL ES。OpenGL 不僅支持包括 OSX,Windows,Linux 和 Android 在內的幾乎所有平臺,還有大量的教程,書籍和最佳實踐指南等資料。目前,Metal 的資源非常有限,並且僅限於搭載了 64 位處理器的 iPhone 和 iPad。但另外一方面,因爲 OpenGL 的限制,其性能與 Metal 相比並不佔優勢,畢竟後者是專門用來解決這些問題的。

如果想要一個 iOS 上高性能的並行計算庫,答案非常簡單。Metal 是唯一的選擇。OpenGL 在 iOS 上是私有框架,而 Core Image (使用了 OpenGL) 對這樣的任務來說既不夠強大又不夠靈活。

6. 適合圖片的蘋果濾鏡框架 -- Core Image

Core Image 是 iOS5 新加入到 iOS 平臺的一個圖像處理框架,提供了強大高效的圖像處理功能, 用來對基於像素的圖像進行操作與分析, 內置了很多強大的濾鏡(Filter) (目前數量超過了180種), 這些Filter 提供了各種各樣的效果, 並且還可以通過 濾鏡鏈 將各種效果的 Filter疊加 起來形成強大的自定義效果。

一個 濾鏡 是一個對象,有很多輸入和輸出,並執行一些變換。例如,模糊濾鏡可能需要輸入圖像和一個模糊半徑來產生適當的模糊後的輸出圖像。

一個 濾鏡鏈 是一個鏈接在一起的濾鏡網絡,使得一個濾鏡的輸出可以是另一個濾鏡的輸入。以這種方式,可以實現精心製作的效果。

iOS8 之後更是支持自定義 CIFilter,可以定製滿足業務需求的複雜效果。

Core Image 的 API 主要就是三類:

  • CIImage 保存圖像數據的類,可以通過UIImage,圖像文件或者像素數據來創建,包括未處理的像素數據。
  • CIFilter 表示應用的濾鏡,這個框架中對圖片屬性進行細節處理的類。它對所有的像素進行操作,用一些鍵-值設置來決定具體操作的程度。
  • CIContext 表示上下文,如 Core Graphics 以及 Core Data 中的上下文用於處理繪製渲染以及處理託管對象一樣,Core Image 的上下文也是實現對圖像處理的具體對象。可以從其中取得圖片的信息。

Core Image 的另外一個優勢,就是可以根據需求選擇 CPU 或者 GPU 來處理。

// 創建基於 CPU 的 CIContext 對象 (默認是基於 GPU,CPU 需要額外設置參數)
context = [CIContext contextWithOptions: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];

// 創建基於 GPU 的 CIContext 對象
context = [CIContext contextWithOptions: nil];

// 創建基於 GPU 的 CIContext 對象
EAGLContext *eaglctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
context = [CIContext contextWithEAGLContext:eaglctx];

7. 適合視頻的第三方濾鏡方案 -- GPUImage

GPUImage 優勢:
最低支持 iOS 4.0,iOS 5.0 之後就支持自定義濾鏡。
在低端機型上,GPUImage 有更好的表現。(這個我沒用真正的設備對比過,GPUImage 的主頁上是這麼說的)
GPUImage 在視頻處理上有更好的表現。
GPUImage 的代碼完成公開,實現透明。
可以根據自己的業務需求,定製更加複雜的管線操作。可定製程度高。

8. 遊戲引擎 -- Scene Kit (3D) 和 Sprite Kit (2D)

對於尋找遊戲引擎的開發者來說,Metal 不是最佳選擇。蘋果官方的的 Scene Kit (3D) 和 Sprite Kit (2D) 是更好的選擇。這些 API 提供了包括物理模擬在內的更高級別的遊戲引擎。

另外還有功能更全面的 3D 引擎,例如 Epic 的 Unreal Engine 或 Unity,二者都是跨平臺的。使用這些引擎,你無需直接使用 Metal 的 API,就可以從 Metal 中獲益。

2D渲染 -- SpriteKit

SpriteKit 讓開發者可以開發高性能、省電節能的 2D 遊戲。在 iOS 8 中,我們新添了多項增強功能,這將使 2D 遊戲體驗更加精彩。這些新技術有助於使遊戲角色的動作更加自然,並讓開發者可以更輕鬆地在遊戲中加入力場、檢測碰撞和生成新的燈光效果。

3D渲染 -- SceneKit

SceneKit 專爲休閒 3D 遊戲而設計,可讓開發者渲染 3D 遊戲場景。SceneKit 內置了物理引擎、粒子發生器和各種易用工具,可以輕鬆快捷地爲 3D 物體編寫動作。不僅如此,它還與 SpriteKit 完全集成,所以開發者可以直接在 3D 遊戲中加入 SpriteKit 的素材。

9. 計算機視覺在iOS的應用 -- OpenCV for iOS

OpenCV 的 API 是 C++ 的。它由不同的模塊組成,這些模塊中包含範圍極爲廣泛的各種方法,從底層的圖像顏色空間轉換到高層的機器學習工具。這裏提供一個入門PDF文檔 下載入口

使用 C++ API 並不是絕大多數 iOS 開發者每天都做的事,你需要使用 Objective-C++ 文件來調用 OpenCV 的函數。 也就是說,你不能在 Swift 或者 Objective-C 語言內調用 OpenCV 的函數。 這篇 OpenCV 的 iOS 教程告訴你只要把所有用到 OpenCV 的類的文件後綴名改爲 .mm 就行了,包括視圖控制器類也是如此。這麼幹或許能行得通,卻不是什麼好主意。正確的方式是給所有你要在 app 中使用到的 OpenCV 功能寫一層 Objective-C++ 封裝。這些 Objective-C++ 封裝把 OpenCV 的 C++ API 轉化爲安全的 Objective-C API,以方便地在所有 Objective-C 類中使用。

走封裝的路子,你的工程中就可以只在這些封裝中調用 C++ 代碼,從而避免掉很多讓人頭痛的問題,比如直接改文件後綴名會因爲在錯誤的文件中引用了一個 C++ 頭文件而產生難以追蹤的編譯錯誤。

OpenCV 聲明瞭命名空間 cv,因此 OpenCV 的類的前面會有個 cv:: 前綴,就像 cv::Mat、 cv::Algorithm 等等。你也可以在 .mm 文件中使用 using namespace cv 來避免在一堆類名前使用 cv::前綴。但是,在某些類名前你必須使用命名空間前綴,比如 cv::Rect 和 cv::Point,因爲它們會跟定義在 MacTypes.h 中的 Rect 和 Point 相沖突。儘管這只是個人偏好問題,我還是偏向在任何地方都使用 cv::以保持一致性。

一般講的OpenCV是基於CPU的,相關資料和支持也是最完善的。當然,也有基於GPU模塊,但提供的接口非常坑爹,相當一部分不支持浮點類型(像histogram、integral這類常用的都不支持);又如,遇到閾值判斷的地方,就必須傳回cpu處理,因爲gpu函數都是並行處理的,每改寫完一個算法模塊,就測試一下運行效率,有的時候是振奮人心,有的時候則是當頭棒喝——比CPU還慢。詳情可參閱 這裏

10. 參考文獻

  • Core Animations

https://www.sohu.com/a/203987045_468740
https://blog.csdn.net/huangznian/article/details/42919221
https://www.jianshu.com/p/446a6b72f981
https://www.jianshu.com/p/439e158b44de

  • Metal

https://juejin.im/post/59ad5d6551882539255b4809
https://www.jianshu.com/p/ce53d0178f20
https://blog.csdn.net/pizi0475/article/details/50232029
https://baike.baidu.com/item/Metal/10917053?fr=aladdin
https://zhuanlan.zhihu.com/p/24623380?utm_source=tuicool&utm_medium=referral

  • Core Image

https://objccn.io/issue-21-6/
http://colin1994.github.io/2016/10/21/Core-Image-OverView/?utm_source=tuicool&utm_medium=referral
https://blog.csdn.net/jingcheng345413/article/details/54967640
https://www.cnblogs.com/try2do-neo/p/3601546.html

  • Core Graphics

https://www.jianshu.com/p/e7a50dcbe7c8
https://www.jianshu.com/p/55cc1587e618
https://www.jianshu.com/p/494c57f49479
https://my.oschina.net/flyfishbay/blog/1504698

  • OpenCV

https://blog.csdn.net/zhonggaorong/article/details/78191514
http://www.opencv.org.cn/forum.php?mod=viewthread&tid=33549
https://blog.csdn.net/kelvin_yan/article/details/41804357
https://blog.csdn.net/sinat_31135199/article/details/53053188
https://blog.csdn.net/liyuefeilong/article/details/46292339

  • GPUImage

https://blog.csdn.net/fanbird2008/article/details/51707430

  • 其它

https://blog.csdn.net/goohong/article/details/40743883

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章