iOS 利用 Metal 實現濾鏡與動效濾鏡

Harbeth 是 Apple 的 Metal 框架上的一小部分實用程序和擴展,致力于使您的 Swift GPU 代碼更加簡潔,讓您更快地構建管道原型。本文就來介紹與設計基于GPU的濾鏡,圖形處理和濾鏡制作...??????

功能清單

?? 目前,Metal Moudle 最重要的特點可以總結如下:

  • 支持運算符函數式操作
  • 支持快速設計濾鏡
  • 支持輸出源的快速擴展
  • 支持相機采集特效
  • 支持矩陣卷積
  • 濾鏡部分大致分為以下幾個模塊:

總結下來目前共有100+種濾鏡供您使用。

  • 代碼零侵入注入濾鏡功能,
原始代碼:
ImageView.image = originImage

注入濾鏡代碼:
let filter = C7ColorMatrix4x4(matrix: Matrix4x4.sepia)
ImageView.image = try? originImage.make(filter: filter)
  • 相機采集生成圖片
注入邊緣檢測濾鏡
var filter = C7EdgeGlow()
filter.lineColor = UIColor.blue

生成相機采集器
let collector = C7FilterCollector(callback: {
    self.ImageView.image = $0
})
collector.captureSession.sessionPreset = AVCaptureSession.Preset.hd1280x720
collector.filter = filter
ImageView.layer.addSublayer(collector)

主要部分

  • 核心,基礎核心板塊

    • C7FilterProtocol:濾鏡設計必須遵循此協議。
      • modifier:編碼器類型和對應的函數名稱。
      • factors:設置修改參數因子,需要轉換為Float
      • otherInputTextures:多個輸入源,包含MTLTexture的數組
      • outputSize:更改輸出圖像的大小。
  • 輸出,輸出板塊

    • C7FilterOutput:輸出內容協議,所有輸出都必須實現該協議。
      • make:根據濾鏡處理生成數據。
      • makeGroup:多個濾鏡組合,請注意濾鏡添加的順序可能會影響圖像生成的結果。
    • C7FilterImage:基于C7FilterOutput的圖像輸入源,以下模式僅支持基于并行計算的編碼器。
    • C7FilterTexture: 基于C7FilterOutput的紋理輸入源,輸入紋理轉換成濾鏡處理紋理。

設計濾鏡

  • 下面我們就第一款濾鏡來分享一下如何設計處理
  1. 實現協議 C7FilterProtocal
public protocol C7FilterProtocol {
     /// 編碼器類型和對應的函數名
     ///
     /// 計算需要對應的`kernel`函數名
     /// 渲染需要一個`vertex`著色器函數名和一個`fragment`著色器函數名
     var modifier: Modifier { get }
    
     /// 制作緩沖區
     /// 設置修改參數因子,需要轉換為`Float`。
     var factors: [Float] { get }
    
     /// 多輸入源擴展
     /// 包含 `MTLTexture` 的數組
     var otherInputTextures: C7InputTextures { get }
    
     /// 改變輸出圖像的大小
     func outputSize(input size:C7Size)-> C7Size
}
  1. 編寫基于并行計算的核函數著色器。
  2. 配置傳遞參數因子,僅支持Float類型。
  3. 配置額外的所需紋理。

舉個例子

設計一款靈魂出竅濾鏡,

Soul.gif
public struct C7SoulOut: C7FilterProtocol {
    
    /// The adjusted soul, from 0.0 to 1.0, with a default of 0.5
    public var soul: Float = 0.5
    public var maxScale: Float = 1.5
    public var maxAlpha: Float = 0.5
    
    public var modifier: Modifier {
        return .compute(kernel: "C7SoulOut")
    }
    
    public var factors: [Float] {
        return [soul, maxScale, maxAlpha]
    }
    
    public init() { }
}
  • 此過濾器需要三個參數:

    • soul:調整后的靈魂,從 0.0 到 1.0,默認為 0.5
    • maxScale:最大靈魂比例
    • maxAlpha:最大靈魂的透明度
  • 編寫基于并行計算內核函數

kernel void C7SoulOut(texture2d<half, access::write> outputTexture [[texture(0)]],
                      texture2d<half, access::sample> inputTexture [[texture(1)]],
                      constant float *soulPointer [[buffer(0)]],
                      constant float *maxScalePointer [[buffer(1)]],
                      constant float *maxAlphaPointer [[buffer(2)]],
                      uint2 grid [[thread_position_in_grid]]) {
    constexpr sampler quadSampler(mag_filter::linear, min_filter::linear);
    const half4 inColor = inputTexture.read(grid);
    const float x = float(grid.x) / outputTexture.get_width();
    const float y = float(grid.y) / outputTexture.get_height();

    const half soul = half(*soulPointer);
    const half maxScale = half(*maxScalePointer);
    const half maxAlpha = half(*maxAlphaPointer);

    const half alpha = maxAlpha * (1.0h - soul);
    const half scale = 1.0h + (maxScale - 1.0h) * soul;

    const half soulX = 0.5h + (x - 0.5h) / scale;
    const half soulY = 0.5h + (y - 0.5h) / scale;

    const half4 soulMask = inputTexture.sample(quadSampler, float2(soulX, soulY));
    const half4 outColor = inColor * (1.0h - alpha) + soulMask * alpha;

    outputTexture.write(outColor, grid);
}
  • 簡單使用,由于我這邊設計的是基于并行計算管道,所以可以直接生成圖片
var filter = C7SoulOut()
filter.soul = 0.5
filter.maxScale = 2.0

/// 直接顯示在ImageView
ImageView.image = try? originImage.makeImage(filter: filter)
  • 至于上面的動效也很簡單,添加一個計時器,然后改變soul值就完事,簡單嘛。

高級用法

  • 運算符鏈式處理
/// 1.轉換成BGRA
let filter1 = C7Color2(with: .color2BGRA)

/// 2.調整顆粒度
var filter2 = C7Granularity()
filter2.grain = 0.8

/// 3.調整白平衡
var filter3 = C7WhiteBalance()
filter3.temperature = 5555

/// 4.調整高光陰影
var filter4 = C7HighlightShadow()
filter4.shadows = 0.4
filter4.highlights = 0.5

/// 5.組合操作
let AT = C7FilterTexture.init(texture: originImage.mt.toTexture()!)
let result = AT ->> filter1 ->> filter2 ->> filter3 ->> filter4

/// 6.獲取結果
filterImageView.image = result.outputImage()
Mix.png
  • 批量操作處理
/// 1.轉換成RBGA
let filter1 = C7Color2(with: .color2RBGA)

/// 2.調整顆粒度
var filter2 = C7Granularity()
filter2.grain = 0.8

/// 3.配置靈魂效果
var filter3 = C7SoulOut()
filter3.soul = 0.7

/// 4.組合操作
let group: [C7FilterProtocol] = [filter1, filter2, filter3]

/// 5.獲取結果
filterImageView.image = try? originImage.makeGroup(filters: group)
Mix2.png

兩種方式都可以處理多濾鏡方案,怎么選擇就看你心情。??

CocoaPods

  • 如果要導入 Metal 模塊,則需要在 Podfile 中:
pod 'Harbeth'
  • 如果要導入 OpenCV 圖像模塊,則需要在 Podfile 中:
pod 'OpencvQueen'

最后

  • 關于濾鏡框架介紹與設計到此為止吧。
  • 慢慢再補充其他相關濾鏡,喜歡就給我點個星??吧。
  • 濾鏡Demo地址,目前包含100+種濾鏡,當然也有大部分濾鏡算法是參考GPUImage設計而來。
  • 再附上一個開發加速庫KJCategoriesDemo地址 ??喜歡的老板們可以點個星??

??.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容