2014年6月26日木曜日

CIFilterのちょっと気の利いた書き方

こんにちは。京都に生まれ育ってン十年。京都の暑さに身体が全く順応せず、毎年クールビズのシーズン間で夏バテしているmatsumiです。

今回のお題は「CIFilterのちょっと気の利いた書き方」です。

CIFilterとはCore Imageで用意されている画像にフィルターをかけるクラスです。
要は、写真系のアプリとかで使われている加工用のいい感じのフィルターを作れますよーってクラスです。
詳しくはAppleのクラスリファレンスあたりをお読みください。

このCIFilter、ちょっと書き方にくせがあって、その辺まとめてる記事があまり無かった気がしたので書いてみます。


まずは、試しにCIFilterで用意してあるフィルターの一種CIVignetteを使った結果です。
元画像
フィルター適用

ビネット効果(トンネルエフェクト)と呼ばれるもので、トイカメラ風の周囲が暗い画像を作る事ができます。


これを「CIFilterの書き方を調べてまず最初に出てくるであろう書き方」で書くと以下の書き方になります。(画像はCIImageにして使います)

CIFilter *ciFilter = [CIFilter filterWithName:@"CIVignette" 
                      keysAndValues:kCIInputImageKey, ciImage,
                      @"inputRadius”, [NSNumber numberWithFloat:200.0f],
                      @"inputIntensity", [NSNumber numberWithFloat:2.0f],
                      nil ];

こんな風に書くのですが、これがちょっと使い勝手が悪いところがありまして、ポイントはフィルター名やパラメータ名が全て文字列で書いてある所です。

これらの部分はフィルター毎に変わるため、複数のフィルターを使用する場合はフィルター数ぶん同じような処理を書いてやる必要があります。

使うフィルターの数が少ないアプリであればそれほど問題ではないのですが、Core Imageの数あるフィルターをフル活用しようとすると、結構な量のコーディングを強いられるため、非常に面倒臭い事になってしまいます。


そんな手間を前に僕らは指をくわえて従うしかないのか?
......といった事は全然なく、以下の書き方もできたりします。

CIFilter *ciFilter = [CIFilter filterWithName:@“CIVignette"];
[ciFilter setDefaults];
[ciFilter setValue:ciImage forKey:@"inputImage"];
[ciFilter setValue:[NSNumber numberWithFloat:200.0f] forKey:@"inputRadius"];
[ciFilter setValue:[NSNumber numberWithFloat:2.0f] forKey:@"inputIntensity"];

これの何が素晴らしいかと言うと、パラメータの数だけsetValueを繰り返す書き方にできるので各フィルターのパラメータ数がまちまちでもFor文を使えば同じ書き方にできてしまう事です。

というか、以下の書き方もできるのでNSDictionaryを使ってしまったらぶっちゃけもっと楽です。

NSDictionary *dicParams = [[NSDictionary alloc]initWithObjectsAndKeys:
                           [NSNumber numberWithFloat:200.0f],@"inputRadius",
                           [NSNumber numberWithFloat:2.0f],@"inputIntensity",
                           nil];
CIFilter *ciFilter = [CIFilter filterWithName:vignette.filterName];
[ciFilter setDefaults];
[ciFilter setValue:ciImage forKey:@"inputImage"];
[ciFilter setValuesForKeysWithDictionary:dicParams];

こんな感じで。
まあ、上記の書き方でもDictionaryを用意するために、少なくても一度は各フィルターのフィルター名とパラメータを書く必要があるのでそれはそれで手間な訳ですが、少なくともCIFilterを作る部分は共通の書き方ができますよーというお話でした。


あ、ちなみに上のサンプルで書いている、

[ciFilter setDefaults];

コレですが、 これを使うと、対応したフィルターのパラメータをデフォルト値で設定してくれる便利な代物です。
これを使ってから、変えたいパラメータだけ設定してやるのがスマートな書き方でしょうか。

それにしてもCoreImageは楽しい。
ちょっと反映が遅かったりするのですが、その辺りはまた別の機会にでも書きたいと思います。


0 件のコメント:

コメントを投稿