はじめに
iOSでフィルターなどの画像処理をする際にフレームワークを用いると実装がとても楽になります。
代表的なものとしてGPUImage3やCore Imageがあります。
そこでそれぞれのフレームワークでカスタムフィルターを試した際の注意した点をまとめてみました。
Core Image編はこちらにあります。
フレームワークについて
GPUImage3
Metalを使用したGPUアクセラレーションによるビデオおよび画像処理用のBSDライセンスのSwiftフレームワークです。https://github.com/BradLarson/GPUImage3
カスタムフィルターの作成
今回作成したのは、特定の色を取得してその部分を違う色に変換するという簡単なフィルターです。
GPUImage3は、Metal Shading Language (MSL)でカスタムフィルターを作成できるので今回はその方法を使用します。
以下の画像のR:128, G:128, B:128の部分を取得して、R:255, G:128, B:20に変換してみます。
以下が実装したコードになります。
・フィルター呼び出し処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//uniform変数使わない場合 //let filter = BasicOperation(fragmentFunctionName:"customFilter", numberOfInputs:1) let filter = CustomFilter() filter.convertColor = Color(red: 255/255, green: 128/255, blue: 20/255) let inputImage = PictureInput(image: image) //image=任意のUIImage let outputImage = PictureOutput() outputImage.imageAvailableCallback = {image in self.processedImageView.image = image //UIImageViewへの表示 } inputImage --> filter --> outputImage inputImage.processImage(synchronously: true) |
・uniform変数を使う場合はclass作成
1 2 3 4 5 6 7 8 9 |
public class CustomFilter: BasicOperation { public var convertColor:Color = Color.red { didSet { uniformSettings["convertColor"] = convertColor } } public init() { super.init(fragmentFunctionName:"customFilter", numberOfInputs:1) ({convertColor = Color.red})(); } } |
・カスタムフィルターの処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <metal_stdlib> #include "OperationShaderTypes.h" using namespace metal; typedef struct { float4 convertColor; } ColorsUniform; fragment half4 customFilter(SingleInputVertexIO fragmentInput [[stage_in]], texture2d<half> inputTexture [[texture(0)]], constant ColorsUniform& uniform [[ buffer(1)]]) { constexpr sampler texSampler; half4 color = inputTexture.sample(texSampler, fragmentInput.textureCoordinate); half3 checkColor = round(color.rgb * 255); half3 convertColor = half3(uniform.convertColor.r, uniform.convertColor.g, uniform.convertColor.b); if ((checkColor.r == 128) && (checkColor.g == 128) && (checkColor.b == 128)) { color = half4(convertColor, 1.0); } return color; } |
実行すると以下の画像のようになります。
注意した点
入力画像にカラー画像を使用する場合は問題ないのですが、
今回のように入力画像に白黒画像を使用したい場合に、カラーモードがインデックスカラーであると
GPUImage3内に書かれているMetalのTextureLoad部分でエラーになってしまいます。
フィルターをかける前にカラーモードがインデックスカラーになっていないことを確認してあげる必要があります。
Failed loading image textureのエラーが出たら確認してみてください。
次の記事では、Core Imageでのカスタムフィルターの作成について書いています。
よかったら見てみてください。