前記事に引き続き、
iOSでフィルターなどの画像処理をする際にフレームワークで
カスタムフィルターを試した際の注意した点をまとめた記事になります。
この記事はCore Image編になります。
GPUImage編はこちらにあります。
フレームワークについて
Core Image
Appleが提供するフレームワークで100種類以上のフィルターがあります。
こちらがCIFilterの一覧です。https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html
カスタムフィルターの作成
GPUImage編と同様に特定の色を取得してその部分を違う色に変換するという簡単なフィルターを作成します。
Core Imageでは、iOS11からMetal Shading Language (MSL)でカスタムフィルターを作成できるようになったのでその方法を使用します。
GPUImage3と同じMSLでの方法ですが、metalファイルのコードには若干違いがあります。
以下の画像のR:128, G:128, B:128の部分を取得して、R:255, G:128, B:20に変換してみます。
以下が実装したコードになります。
・フィルター呼び出し処理
1 2 3 4 |
let filter = CustomFilter() filter.inputImage = CIImage(image: image) //image=任意のUIImage self.processedImageView.image = UIImage(ciImage: filter.outputImage()!) //UIImageViewへの表示 |
・metalファイル呼び出しのためのクラスを作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class CustomFilter: CIFilter { private let kernel: CIColorKernel var inputImage: CIImage? override init() { let url = Bundle.main.url(forResource: "default", withExtension: "metallib")! let data = try! Data(contentsOf: url) kernel = try! CIColorKernel(functionName: "customFilter", fromMetalLibraryData: data) super.init() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func outputImage() -> CIImage? { guard let inputImage = inputImage else {return nil} return kernel.apply(extent: inputImage.extent, arguments: [inputImage]) } } |
・カスタムフィルターの処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <metal_stdlib> using namespace metal; #include <CoreImage/CoreImage.h> extern "C" { namespace coreimage { half4 customFilter(sample_h sample) { half4 color = sample.rgba; half3 checkColor = round(linear_to_srgb(color.rgb) * 255); half3 convertColor = half3(255.0/255.0, 128.0/255.0, 20.0/255.0); if ((checkColor.r == 128) && (checkColor.g == 128) && (checkColor.b == 128)) { color = half4(srgb_to_linear(convertColor), 1.0); } return color; } }} |
実装が終わったらビルドする前にBuild Settingsで以下を設定します。
・Other Metal Compiler Flagsに-fcikernelを指定。
・User-Defined SettingでMTLLINKER_FLAGSを追加して-cikernelを指定します。
注意した点
Core Imageでは、デフォルトで入力画像の色空間がリニア色空間で扱われるので色を取得する際に注意する必要があります。
例えば、取得したい色のRGB値がsRGB色空間のものである場合には、linear_to_srgb()関数で変換してあげることで取得できるようになります。またsRGB色空間のRGB値で指定したい場合には、srgb_to_linear()関数でリニア色空間にしてから出力します。
リニア色空間にしないと以下の画像の左のような色で出力されてしまいます。右の画像が期待通りの状態です。
最後に
GPUImage3もCore Imageも両方ともフィルターが豊富かつフィルターの重ねがけが可能なので、
フィルター組み合わせ次第でいろんなバリエーションを生み出せますが、
自分の用途に合わせてカスタムフィルターを作成したい時の参考になれば幸いです。