33
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOS2Advent Calendar 2017

Day 6

CIKernel を使用してCore Imageのカスタムフィルタをつくる

Last updated at Posted at 2014-06-30

Core Image の CIFilter を使うといろいろなフィルタ処理(画像処理/画像加工)ができますが、iOS 8で CIKernel というクラスが追加され、そのフィルタ(CIFilter)を自作できるようになりました。

以下、CIKernel のフィルタ処理を記述し、それを使ってオリジナルの CIFilter を定義し、画像に適用するまでの手順です。

(更新履歴)本記事は2014年のiOS 8がまだベータ版だった頃に書いたもので、Objective-Cコードは古くなっている可能性があります。Swiftコードは2017年12月に追記したもので、Swift 4対応です。

CIKernel をつくる

カーネルを書く

カーネルはGLSLのサブセットで書きます。

kernel vec4 swapRedAndGreenAmount ( __sample s, float amount )
                  { return mix(s.rgba, s.grba, amount); }

CIKernelオブジェクトを生成する

上記で書いたシェーダを 文字列として CIKernel の初期化メソッドに渡します

objc
CIKernel *kernel = [CIKernel kernelWithString:kernelStr];
swift
let kernel = CIColorKernel(source: kernelStr)!

CIFilter サブクラスをつくる

上記で生成した CIKernel オブジェクトを使用して、CIFilter サブクラスをつくります。

ヘッダには下記のようにプロパティを定義します。

MyFilter.m
@interface MyFilter : CIFilter

@property (nonatomic, strong) CIImage *inputImage;
@property (nonatomic, copy) NSNumber *inputAmount;

@end

実装ファイル側は長くなるので省略しますが、CIKernelを適用して出力する部分はこんな感じす。

MyFilter.m
- (CIImage *)outputImage
{
    return [[self myKernel] applyWithExtent:self.inputImage.extent
                                  arguments:@[self.inputImage, self.inputAmount]];
}

Swift 4で書くと、こんな感じになります。

MyFilter.swift

class MyFilter: CIFilter {

    private let kernelStr =
    "kernel vec4 swapRedAndGreenAmount ( __sample s, float amount ) { return mix(s.rgba, s.grba, amount); }"

    private let kernel: CIColorKernel
    
    var inputImage: CIImage?
    var inputAmount: Float = 1.0

    override init() {
        kernel = CIColorKernel(source: kernelStr)!
        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, inputAmount])
    }
}

##画像に適用する

使い方は 普通の CIFilter (ビルトインフィルタ) と同じ

objc
NSDictionary *params = @{kCIInputImageKey: ciImage,
                         @"inputAmount": @(1.0),
                         };
CIFilter *filter = [CIFilter filterWithName:@"MyFilter"
                        withInputParameters:params];

Swift 4の場合:

swift
let filter = MyFilter()
filter.inputImage = inputImage
let outputImage = filter.outputImage()

###実行結果

results.jpg

(左:元画像 右:カスタムフィルタ適用後の画像)

##参考資料

  • Developing Core Image Filter for iOS (WWDC 2014 Session 515)
  • CIKernel Class Reference
  • Core Image Kernel Language Reference

##関連記事

ちょっと古いものもありますが、Core Image、画像処理関連の記事は他にもいろいろと書いているので、よろしければご参照ください。

33
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?