Harbeth 是 Apple 的 Metal 框架上的一小部分實用程序和擴展,致力于使您的 Swift GPU 代碼更加簡潔,讓您更快地構建管道原型。本文就來介紹與設計基于GPU的濾鏡,圖形處理和濾鏡制作...??????
功能清單
?? 目前,Metal Moudle 最重要的特點可以總結如下:
- 支持運算符函數式操作
- 支持快速設計濾鏡
- 支持輸出源的快速擴展
- 支持相機采集特效
- 支持矩陣卷積
- 濾鏡部分大致分為以下幾個模塊:
- Blend:圖像融合技術
- Blur:模糊效果
- ColorProcess:圖像的基本像素顏色處理
- Effect:效果處理
- Lookup:查找表過濾器
- Matrix: 矩陣卷積濾波器
- Shape:圖像形狀大小相關
- VisualEffect: 視覺動態特效
總結下來目前共有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:更改輸出圖像的大小。
-
C7FilterProtocol:濾鏡設計必須遵循此協議。
-
輸出,輸出板塊
-
C7FilterOutput:輸出內容協議,所有輸出都必須實現該協議。
- make:根據濾鏡處理生成數據。
- makeGroup:多個濾鏡組合,請注意濾鏡添加的順序可能會影響圖像生成的結果。
- C7FilterImage:基于C7FilterOutput的圖像輸入源,以下模式僅支持基于并行計算的編碼器。
- C7FilterTexture: 基于C7FilterOutput的紋理輸入源,輸入紋理轉換成濾鏡處理紋理。
-
C7FilterOutput:輸出內容協議,所有輸出都必須實現該協議。
設計濾鏡
- 下面我們就第一款濾鏡來分享一下如何設計處理
- 實現協議
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
}
- 編寫基于并行計算的核函數著色器。
- 配置傳遞參數因子,僅支持
Float
類型。 - 配置額外的所需紋理。
舉個例子
設計一款靈魂出竅濾鏡,
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地址 ??喜歡的老板們可以點個星??
??.