プログラミング教室で Core Image を使った画像処理について説明しました

[前回](http://qiita.com/mironal/items/c3b0dc005de335b48e32)

---

## 概要

- 今回は趣向を変えて iOS アプリというより画像処理に焦点を当てます
- Core Image を使用して Swift が画像処理を行います
- CIDetector を使って顔検出を行います
- ちなみに俺はそんなに画像処理について詳しくない

## 画像処理

> 画像処理（がぞうしょり、Image processing）とは、電子工学的（主に情報工学的）に画像を処理して、別の画像に変形したり、画像から何らかの情報を取り出すために行われる処理全般を指す

[https://ja.wikipedia.org/wiki/画像処理](https://ja.wikipedia.org/wiki/%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86)

画像の色を変えたり、変形・回転させる他にもエッジ検出をしたりすることも画像処理です。

伝統的には画像を RGB に分解して3次元の配列として色々計算したりしてました。

```c
for (int b = 0; b < size; b++) {
    for (int g = 0; g < size; r++) {
        for (int r = 0; r < size; r ++) {
            cubeData[b][g][r] = <# output R value #>;
            cubeData[b][g][r] = <# output G value #>;
            cubeData[b][g][r] = <# output B value #>;
            cubeData[b][g][r] = <# output A value #>;
        }
    }
}
```

これをやるのは非常に大変なので予め用意されたライブラリを使ってお手軽に画像処理を行います。

## Core Image ?

Core Image は Apple が提供している画像処理の Framework です。

フィルタというものを使って画像や動画に色々な視覚効果(ぼかしとか)を適用することができます。

フィルタは最初から170個以上入っています。 独自のカスタムフィルタを作ることも可能です。

[フィルタのドキュメント(サンプル画像もあるのでどのような効果なのか確認できます)](https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html)

[いろいろな例](https://github.com/FlexMonkey/Filterpedia)

## やること

Xcode の Playground を使って swift で画像処理のコードを書いていきます。

自分の好きな画像を用意します(カラーでそんなにサイズが大きくないものが良いです)。

用意した画像は playground の左のツリーの Resources フォルダにドラッグしておきます。

### 画像処理の流れ

画像処理は元画像にフィルタを通して加工済み画像を作ります。 カッコ内は使用するクラス名です。 CI は Core Image の略です。

```
元画像(CIImage) -> フィルタ(CIFilter) -> 加工済み画像(CIImage)
```

フィルタにはパラメータがある場合があります。 パラメータによって例えば画像のぼかし具合を変えたりすることができます。

### 白黒画像にしてみる

`CIPhotoEffectMono` というフィルタを使います。

画像のファイル名("Lenna.jpg")は自分の画像のファイル名に合わせてください。

```swift
import UIKit

let image = UIImage(named: "Lenna.jpg")!
let ciImage = CIImage(image: image)

let filter = CIFilter(name: "CIPhotoEffectMono")!

filter.setDefaults()
filter.setValue(ciImage, forKey: kCIInputImageKey)

let output = filter.outputImage
```

プレビューを出すには画像の変数の行の右側の + ボタンを押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/0874f35d-65b4-1b8a-183b-58e6c374ed51.png)

このフィルタにはパラメータはありません。

### ぼかし

`CIBoxBlur` というフィルタを使います。

さっきのコードの

```swift 
let filter = CIFilter(name: "CIPhotoEffectMono")!
```

の部分を

```swift
let filter = CIFilter(name: "CIBoxBlur")! 
```

にしてみます。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/0fe1dcbf-2110-308e-7a8d-052c30078fcd.png)

このフィルタにはパラメータがあります。

- `kCIInputRadiusKey(inputRadius)`: ぼかしの表示半径の数値. デフォルトは 10.

パラメータは `outputImage` の前に `filter.setValue(50, forKey: kCIInputRadiusKey)` と書いて設定します。

以下は kCIInputRadiusKey を 50 にした例(output1)です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/69dedf6c-6170-07df-24a8-e2da3e5da058.png)

他にも以下のように沢山のフィルタがあるので色々試してみよう。

```
CIBoxBlur
CIDiscBlur
CIGaussianBlur
CIMaskedVariableBlur
CIMedianFilter
CIMotionBlur
CINoiseReduction
CIZoomBlur
```

### エッジ検出

色々あるけど `CIEdges` を使ってみる。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/6d902f16-271a-70db-323e-990f84d2ccd3.png)

### 歪ませる

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/aeff7b3b-2d02-e59b-048e-3160f5cf52e1.png)


### 回転

`CIStraightenFilter` を使う。

`kCIInputAngleKey` で角度(ラジアン)を指定する。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/c46e0abd-9b49-488d-79ef-acb45439d9b5.png)

## 拡大縮小

`CILanczosScaleTransform` を使う。

`kCIInputScaleKey` で倍率を指定する。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/04cf1995-9ed9-0ab3-c60a-97fffe78556b.png)

## 遷移アニメーション

1枚目の画像から2枚目の画像に遷移する画像を生成できる。 アニメーションするためには自分で制御する必要がある。

`CIModTransition` を使う。

`kCIInputTimeKey` をいじるとだんだん遷移するエフェクトが確認できる。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/163959d1-4cf2-9cb3-6023-fcb843f6c407.png)


## 顔検出

`CIDetector` を使用して顔検出を行う。

```swift 
import UIKit

let image = UIImage(named: "Lenna.jpg")!
let ciImage = CIImage(image: image)


let detector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: nil)
let features = detector.featuresInImage(ciImage!)

let imageView = UIImageView(image: image)

if let first = features.first {

    let bounds = CGRect(x: first.bounds.origin.x,
                        // 原点[0, 0] が左下にあるので反転させる(UI は原点が左上).
                        y: image.size.height - (first.bounds.height + first.bounds.origin.y),
                        width: first.bounds.width,
                        height: first.bounds.height)

    let faceRectView = UIView(frame: bounds)
    faceRectView.layer.borderWidth = 1.0
    faceRectView.layer.borderColor = UIColor.redColor().CGColor
    imageView.addSubview(faceRectView)
    
}
```

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/2a66ace1-8fdd-6553-2b13-13caaf17a919.png)


## まとめ

- Core Image を使って画像処理について学びました
- ボカシ処理などの簡単な加工ができるようなりました
- 画像の顔検出もできるようになりました
- Playground のプレビュー機能を使って動作を確認しながらプログラミングを行う方法を学びました

開催場所: TENTO さいたま