LoginSignup
31
32

More than 5 years have passed since last update.

CIFilter, OpenCV, vImageを使って画像フィルタ処理をかける

Last updated at Posted at 2013-05-11

f:id:himaratsu:20130429015624j:plain f:id:himaratsu:20130429015629j:plain

Instagramなどの写真アプリでよくある画像フィルタを作ってみます。

調べたところ、大きく3つの方法があるようです。

  • CIFilter を使う方法
  • OpenCV を使う方法
  • vImage を使う方法

それぞれについて、コードを交えて説明を書きます。

CIFilterを使う方法

CIFilterとは、iOS 5以降で使えるようになった、CoreImage.frameworkが提供する機能です。

CIFilterのかけ方

  • 元画像(UIImageクラス)をCIImageオブジェクトに変換
  • CIFilterオブジェクトを作る
  • CIFilterのoutputImageプロパティから、フィルタ後の画像を取得
  • 取得した画像データ(CIImage)をUIImageに変換する

ソース

// 元画像を取得
UIImage *originImage = [UIImage imageNamed:@"sample.png"];

// UIImageをCIImageに変換
CIImage *filteredImage = [[CIImage alloc] initWithCGImage:originImage.CGImage];

// CIFilterを作成(今回はモノクロ風フィルタをかけます)
CIFilter *filter = [CIFilter filterWithName:@"CIMinimumComponent"];
[filter setValue:filteredImage forKey:@"inputImage"];

// フィルタ後の画像を取得
filteredImage = filter.outputImage;

// CIImageをUIImageに変換する
CIContext *ciContext = [CIContext contextWithOptions:nil];
CGImageRef imageRef = [ciContext createCGImage:filteredImage
                                      fromRect:[filteredImage extent]];
UIImage *outputImage  = [UIImage imageWithCGImage:imageRef
                                            scale:1.0f
                                      orientation:UIImageOrientationUp];
CGImageRelease(imageRef);

// 表示
[self.view addSubview:outputImage];

どのフィルタを使うかは CIMinimumComponent の部分で指定できます。
フィルタによっては、強度や露光量などのパラメータを設定できるものもあります。
その場合は、

[filter setValue:[NSNumber numberWithFloat:1.0] forKey:@"inputIntensity"];
[filter setValue:[NSNumber numberWithFloat:2.0] forKey:@"inputRadius"];

のように、CIFilterオブジェクトにセットしていけばOKです。

実行結果

実行前

f:id:himaratsu:20130429015624j:plain

実行後

f:id:himaratsu:20130429015629j:plain

もっと詳しく知りたい

OpenCVを使う方法

OpenCVとは、画像処理・画像認識のために作られたオープンソースのC言語ライブラリです。

OpenCVを使うためのフレームワークはiOS標準搭載ではないので、

ここからダウンロードしてプロジェクトに追加する必要があります。

以前はソースをコンパイルして扱う必要があったようですが、

今はフレームワークが使えるようになったので楽チンです。

OpenCVの使い方

  • 元画像(UIImageクラス)をIplImageオブジェクトに変換
  • IplImageにごにょごにょと操作を加える
  • フィルタ後のデータ(IplImage)をUIImageに変換する

ソース

著者はOpenCVに不慣れなため、参考リンクを貼ることにします。

変換から実際のフィルタリングまで、丁寧で非常に分かりやすいです。

OpenCVで写真を漫画風に加工しよう 〜実装編〜 | Developers.IO

実行結果

実行前

f:id:himaratsu:20130429015624j:plain

実行後

f:id:himaratsu:20130429023209j:plain

もっと詳しく知りたい

vImageを使う方法

vImageとは、iOS 5以降で使えるようになった、Accelerate frameworkが提供する機能です。

iOSデバイスのハードウェア向けに最適化されており、高速に処理できると言われています。

vImageの使い方

  • 描画領域の確保など前準備を行う
  • 画像フィルタ処理(畳み込み演算)をかける
  • フィルタ後のデータを取得する

ソース

// 描画領域の確保など、前準備
const size_t width = _originImage.size.width;
const size_t height = _originImage.size.height;
const size_t bytesPerRow = width * 4;

CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst;
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8,
                                               bytesPerRow, space,
                                               bitmapInfo);
CGColorSpaceRelease(space);

if (!bmContext) {
    return;
}

CGRect dstRect = CGRectMake(0, 0, width, height);
CGContextDrawImage(bmContext, dstRect, _originImage.CGImage);

UInt8 *data = (UInt8 *)CGBitmapContextGetData(bmContext);
if (!data) {
    CGContextRelease(bmContext);
    return;
}

vImage_Buffer src = {data, height, width, bytesPerRow};

// 出力容量確保
const size_t dstSize = sizeof(UInt8) * width * height * 4;
void *dstData = malloc(dstSize);
vImage_Buffer dst = {dstData, height, width, bytesPerRow};

// 今回は先鋭化のフィルタを作る
static int16_t sharpen_kernel[9] = {
    -1, -1, -1,
    -1, 9, -1,
    -1, -1, -1
};

// たたみこみ演算
vImageConvolve_ARGB8888(&src,
                        &dst,
                        NULL,
                        0,
                        0,
                        sharpen_kernel,
                        3,
                        3,
                        1,
                        NULL,
                        kvImageCopyInPlace);

// 処理結果をUIImageに格納
memcpy(data, dstData, dstSize);
free(dstData);

CGImageRef blurredImageRef = CGBitmapContextCreateImage(bmContext);
UIImage* blurred = [UIImage imageWithCGImage:blurredImageRef];

CGImageRelease(blurredImageRef);
CGContextRelease(bmContext);

[self.view addSubview:blurred];

vImageConvolve_ARGB8888 の第6変数に渡す配列を変化させることでフィルタを選択できます。

(画像処理の知識が必要となりますね)

実行結果

実行前

f:id:himaratsu:20130429015624j:plain

実行後

f:id:himaratsu:20130429023124j:plain

もっと詳しく知りたい

まとめ

  • CIFilter、OpenCV、vImageを使って画像フィルタを行った
  • CIFilterは画像処理の知識なしにフィルタを選ぶだけでOK
  • OpenCV、vImageは画像処理の知識があれば複雑な処理もかけられる

元記事

31
32
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
31
32