pix2pixでCFAデモザイクを試してみる

# pix2pixでCFAデモザイクを試してみる

## はじめに
画像から画像を生成する敵対的生成ネットワーク「pix2pix」を使って、ベイヤー画像からカラー画像を生成するデモザイクを試してみます。

## デモザイク処理とは
デジタルカメラのイメージセンサーは、各ピクセルに当たる光の「色」を直接検出することはできません。センサーが検出できるのは各ピクセルに当たる光の「明るさ」情報です。色情報を得るためには、画素の前に特定の色のみを透過するカラーフィルターを配置しています。
カラーフィルタの配色や配置にはさまざまなパターンがありますが、多くのデジタルカメラでは、ベイヤーフィルタと呼ばれるカラーフィルタが採用されています。
[ベイヤーフィルタ（wikipedia）](https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%A4%E3%83%A4%E3%83%BC%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%BC)

![320px-Bayer_pattern_on_sensor.svg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/5930e606-3a48-d649-313f-b055673fc50a.png)

ベイヤーフィルタでは、1画素内の情報は、赤、緑、青のいづれかのチャンネルの情報のみです。このベイヤー画像からフルカラー画像を得るためには、欠損している色情報を周辺のピクセルから予測する必要があります。

この処理をデモザイク処理と呼びます。

デモザイク処理のアルゴリズムは今までさまざまな方法が提案されています。もっともシンプルなアルゴリズムは、線形補間を用いたデモザイク処理です。
このアルゴリズムでは、欠損した色情報を隣接ピクセルから線形補間により求めます。たとえば青の画素位置において、緑色の情報を予想するには、隣接した上下左右の緑画素の信号の平均を求めます。

この方法は、輝度や色が一定の領域や、滑らかに変化する領域であれば、うまくいきます。しかし明るさや色が急激に変化する領域では、画像のボケ（高周波成分の喪失）や、色の滲み（偽色）などの不自然な画像を生成します。

![kodim11-bayer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/43f0a76a-fa7c-4efa-120e-bb3ff579150a.png) ![kodim11-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/78335360-0b8d-832a-9f46-5e1c073a5f0c.png) ![kodim11-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/b120d1c9-30bb-eadb-1dab-980ef9897330.png)
左：ベイヤー画像　中央：線形補間　右：原画像

## pix2pix-tensorflow
今回は、「pix2pix」を使用してデモザイクアルゴリズムを学習させてみます。
「pix2pix」は、いくつかのプラットフォームで実装されていますが、今回はtensorflow版の、「pix2pix-tensorflow」を使用しました。
[affinelayer/pix2pix-tensorflow](https://github.com/affinelayer/pix2pix-tensorflow)

## データセットの準備
「pix2pix」で学習するためには、入力画像であるベイヤー画像と、学習目標画像であるフルカラー画像のペアが枚数必要です。本物のベイヤー画像を準備するのは大変なので、今回は、Web上のフルカラー画像から、擬似的なベイヤー画像を生成します。
フルカラー画像は、以下の画像データを利用しました。
- iaptc12
    http://www-i6.informatik.rwth-aachen.de/imageclef/resources/iaprtc12.tgz
    ネットワークの学習に使用。学習時間の都合上、ディレクトリ39の画像（約1000枚）を使用する。
- Kodak Lossless True Color Image
    http://r0k.us/graphics/kodak/
    デモザイク処理の評価用データセットの定番。 ネットワークの評価用に使用。

## 擬似ベイヤー画像生成
実際のベイヤー画像からフルカラー画像への現像処理では、デモザイク処理だけでなく、ホワイトバランス処理や色再現補正処理、エッジ強調処理、トーンマッピング処理などのさまざまな処理によってフルカラー画像を生成します。フルカラー画像から、「リアル」な疑似ベイヤー画像を得るためには、これらの逆変換処理を行う必要があります。これらの処理はカメラメーカによって異なるため、正確なパラメータを得ることは難しいでしょう。今回は、これらの特性は一切無視して、単純にフルカラー画像を「モザイキング」します。

[colour-demosaicing](https://pypi.org/project/colour-demosaicing/)を参考に、OpenCVのカラーチャンネルオーダ（BGR）に変更しました。また、参照元のベイヤー画像はシングルチャンネルの画像ですが、このコードでは、3チャンネルのベイヤー画像を出力します。欠損した色情報は0として出力します。

```py

def masks_CFA_Bayer(shape, pattern='RGGB'):
    pattern = pattern.upper()
    channels = dict((channel, np.zeros(shape)) for channel in 'BGR')
    for channel, (y, x) in zip(pattern, [(0, 0), (0, 1), (1, 0), (1, 1)]):
        channels[channel][y::2, x::2] = 1
    return tuple(channels[c].astype(bool) for c in 'BGR')

def mosaicing_CFA_Bayer(BGR, pattern='RGGB'):
    B, G, R = cv2.split(BGR)
    B_m, G_m, R_m = masks_CFA_Bayer(BGR.shape[0:2], pattern)
    CFA = cv2.merge((B * B_m, G * G_m, R * R_m))
    return CFA
```

また、「pix2pix-tensorflow」では、画像サイズは256x256で固定されています。これに合わせて、画像の中心部256x256の領域を切り出します。また、「pix2pix-tensorflow」では、入力画像と目標画像を左右に結合して、1枚の画像として学習させます。左側にベイヤー画像、右側にフルカラー画像を配置して、結合します。

## 学習
準備したデータセットを用いて学習します。
「pix2pix-tensorflow」で学習する上で注意すべきパラメータとしては、
- 学習時にスケーリングを行わない（--scale_size 256）
    デフォルトでは、学習時に、286x286に画像をスケーリングしてから中央部256x256をクロッピングしています。
    今回の用途では、この処理の副作用が無視できないため、スケーリングをオフにします。
- 学習時に左右フリップしない（--no_flip）
    ベイヤー画像では左右フリップすると、カラーフィルタのパターンが反転します。（RGGBがGRBGになる）
です。

今回は、約1000枚の学習データに対して、1000エポック学習させました。

## 評価

学習したパラメータをもちいて、評価データセット（Kodak）を現像します。
また、比較のために、線形補間法、[Malvar](https://stanford.edu/class/ee367/reading/Demosaicing_ICASSP04.pdf)、[DFDPD](http://www.danielemenon.netsons.org/pub/dfapd/dfapd.php)で現像します。これらのアルゴリズムは、[colour-demosaicing](https://pypi.org/project/colour-demosaicing/)で実装されています。

定量評価のために、各アルゴリズムでのデモザイク処理と原画像との、PSNRを算出します。

|       |bilinear|malvar|ddfapd|pix2pix|
|-------|-------:|-----:|-----:|------:|
|kodim01|   27.83| 34.08| 37.68|  36.76|
|kodim02|   34.06| 37.92| 42.29|  38.42|
|kodim03|   34.40| 40.01| 42.60|  37.90|
|kodim04|   37.01| 43.48| 46.37|  39.26|
|kodim05|   27.47| 35.93| 39.17|  35.74|
|kodim06|   28.32| 34.58| 38.24|  36.55|
|kodim07|   32.73| 39.97| 42.31|  37.58|
|kodim08|   27.86| 34.64| 38.18|  35.71|
|kodim09|   32.93| 39.76| 45.52|  38.46|
|kodim10|   35.95| 44.71| 46.40|  38.21|
|kodim11|   28.20| 34.84| 37.67|  36.52|
|kodim12|   31.89| 38.86| 43.46|  37.15|
|kodim13|   26.66| 33.56| 35.20|  35.55|
|kodim14|   29.67| 35.04| 37.18|  35.29|
|kodim15|   33.72| 39.02| 39.96|  37.97|
|kodim16|   32.39| 39.15| 43.21|  38.50|
|kodim17|   33.92| 41.16| 44.04|  38.41|
|kodim18|   28.54| 35.50| 36.56|  35.75|
|kodim19|   28.94| 35.46| 41.43|  36.79|
|kodim20|   30.69| 39.13| 41.72|  33.45|
|kodim21|   29.45| 36.13| 38.86|  36.48|
|kodim22|   30.62| 36.31| 39.14|  36.08|
|kodim23|   34.49| 39.79| 44.46|  37.82|
|kodim24|   32.04| 38.39| 39.62|  37.01|
|average|   31.24| 37.81| 40.89|  36.97|

24枚のPSNR平均で出力結果を比較してみます。
bilinearと比較すると、約5.7dBの画質改善となっていますが、malvarと比較すると約1dB、ddfapdと比較すると約3.9dBほどの画質劣化となっています。

"lighthouse(kodim18)"の出力画像を比較してみます

![kodim19-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/9c8330bd-94b6-b1d2-3429-a24c182f6672.png) ![kodim19-pix2pix1000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/d8ed9982-4bb9-5403-a570-2683a40f509b.png) ![kodim19-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/9745548e-c865-a222-ff80-09989895efac.png)　
kodim18　左：線形補間（28.54dB）　中央：pix2pix（35.75dB）　右：原画像

bilinearでは、右下の柵の部分にチェッカー状の偽色が発生しています。また、灯台の壁部分も元画像と比較すると、ボケて見えます。
pix2pixの出力結果は、ボケや、チェッカー状の偽色は発生していません。

## 学習回数増加による性能改善
定量評価では、pix2pixでのdemosaicの出力結果は、既存アルゴリズム（malvar, ddfapd）と比較して劣っていますので、改善を試みます。
単純に、学習時のエポック数を2000まで増やしてみます。

|       |bilinear|malvar|ddfapd|pix2pix|
|-------|-------:|-----:|-----:|------:|
|kodim01|   27.83| 34.08| 37.68|  39.59|
|kodim02|   34.06| 37.92| 42.29|  40.03|
|kodim03|   34.40| 40.01| 42.60|  40.44|
|kodim04|   37.01| 43.48| 46.37|  45.11|
|kodim05|   27.47| 35.93| 39.17|  36.71|
|kodim06|   28.32| 34.58| 38.24|  39.13|
|kodim07|   32.73| 39.97| 42.31|  40.46|
|kodim08|   27.86| 34.64| 38.18|  36.80|
|kodim09|   32.93| 39.76| 45.52|  42.10|
|kodim10|   35.95| 44.71| 46.40|  44.47|
|kodim11|   28.20| 34.84| 37.67|  38.14|
|kodim12|   31.89| 38.86| 43.46|  39.72|
|kodim13|   26.66| 33.56| 35.20|  37.28|
|kodim14|   29.67| 35.04| 37.18|  36.57|
|kodim15|   33.72| 39.02| 39.96|  39.68|
|kodim16|   32.39| 39.15| 43.21|  43.23|
|kodim17|   33.92| 41.16| 44.04|  43.04|
|kodim18|   28.54| 35.50| 36.56|  36.44|
|kodim19|   28.94| 35.46| 41.43|  38.71|
|kodim20|   30.69| 39.13| 41.72|  27.97|
|kodim21|   29.45| 36.13| 38.86|  30.42|
|kodim22|   30.62| 36.31| 39.14|  37.83|
|kodim23|   34.49| 39.79| 44.46|  41.29|
|kodim24|   32.04| 38.39| 39.62|  39.92|
|average|   31.24| 37.81| 40.89|  38.96|

エポック数1000の時点の出力と比較して、平均で2dBほど改善し、malvarとの比較では約1dBほど画質改善となりました。
ddfapdとの比較では、まだ逆転には至らず、約2dBほど劣っています。

## 既存手法との組み合わせによる性能改善

既存手法との組み合わせによって、性能改善を試みます。ベイヤー画像を直接pix2pixで処理するのではなく、線形補間法で補間した画像を入力画像として使用してみました。
こちらも1000エポック学習してみます。

|       |bilinear|malvar|ddfapd|outputs|
|-------|-------:|-----:|-----:|------:|
|kodim01|   27.83| 34.08| 37.68|  39.87|
|kodim02|   34.06| 37.92| 42.29|  39.71|
|kodim03|   34.40| 40.01| 42.60|  40.23|
|kodim04|   37.01| 43.48| 46.37|  45.38|
|kodim05|   27.47| 35.93| 39.17|  36.75|
|kodim06|   28.32| 34.58| 38.24|  39.44|
|kodim07|   32.73| 39.97| 42.31|  40.18|
|kodim08|   27.86| 34.64| 38.18|  37.29|
|kodim09|   32.93| 39.76| 45.52|  42.43|
|kodim10|   35.95| 44.71| 46.40|  45.19|
|kodim11|   28.20| 34.84| 37.67|  38.06|
|kodim12|   31.89| 38.86| 43.46|  40.99|
|kodim13|   26.66| 33.56| 35.20|  37.33|
|kodim14|   29.67| 35.04| 37.18|  36.50|
|kodim15|   33.72| 39.02| 39.96|  39.75|
|kodim16|   32.39| 39.15| 43.21|  42.62|
|kodim17|   33.92| 41.16| 44.04|  43.45|
|kodim18|   28.54| 35.50| 36.56|  36.63|
|kodim19|   28.94| 35.46| 41.43|  39.30|
|kodim20|   30.69| 39.13| 41.72|  35.71|
|kodim21|   29.45| 36.13| 38.86|  39.32|
|kodim22|   30.62| 36.31| 39.14|  37.83|
|kodim23|   34.49| 39.79| 44.46|  41.40|
|kodim24|   32.04| 38.39| 39.62|  40.04|
|average|   31.24| 37.81| 40.89|  39.81|

bilinearと比較すると、約8.6dBの画質改善、malvarとの比較では約2dBほどの画質改善になっています。
ddfapdとの比較では、まだ逆転には至らず、約1dBほど劣っています。

比較画像
![kodim07-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/521e9a37-d645-fa65-12e3-3ae8a1a06178.png) ![kodim07-outputs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/796e851b-2aca-7ba7-5ee1-01fc5c48bcfd.png) ![kodim07-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/45856430-ff61-c12b-d9dc-29af9c253aaf.png)
kodim07 左：線形補間（32.73dB）中央：pix2pix（40.18dB）　右：原画像

![kodim08-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/d02c664e-a020-74ea-753b-9a59f8525c7b.png) ![kodim08-outputs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/452e6ae0-06db-3bbf-846d-a95f19f0f592.png) ![kodim08-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/da3cdf83-f154-18ca-023b-b01388806164.png)
kodim08 左：線形補間（27.86dB）中央：pix2pix（37.29dB）　右：原画像

![kodim11-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/5502926b-9db4-fd69-5276-6c7603a8bacd.png) ![kodim11-outputs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/d67cbe0b-a0fd-7780-0f2b-296bdb78207a.png) ![kodim11-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/615189e6-f5b1-1d2f-48db-00be3f00e740.png)
kodim11 左：線形補間（28.20dB）中央：pix2pix（38.06dB）右：原画像

![kodim19-bilinear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/be9bb889-58af-1292-eb23-86888d2c8394.png) ![kodim19-outputs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/ce42a9b6-cb67-bfcd-c0a9-e03fdf7ff78b.png) ![kodim19-targets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374867/31e9f50e-8034-578d-334f-b0d628fa093c.png)
kodim19 左：線形補間（28.94dB）　中央：pix2pix（39.30dB）　右：原画像

## まとめ
pix2pixを、ベイヤー画像からカラー画像への変換に応用してみました。人間が考案したさまざまなアルゴリズムと比較しても、遜色のない画質の画像を得ることができました。さらなる画質改善を行うためには、ジェネレータやディスクミネータの損出関数の見直しや、ネットワーク構成の見直しなどが考えられます。しかし、それらの工夫よりも、”より良質なデータセット”で”より多くのエポック数で学習”した方が、より良い結果が得られるかもしれません。

また、今回はデモザイク処理にフォーカスして学習させました。CNNを使った例では、デモザイク処理とデノイズ処理とを融合させた例などなどもあります。
[Joint demosaicing and denoising of RAW images with a CNN](https://kunzmi.github.io/NNDemosaicAndDenoise/)
こちらは、損出関数としてL1normとSIMMの混合指標によりCNNを学習しており、敵対的生成ネットワークではありませんが、デモザイク処理とデノイズ処理の融合にもpix2pixは応用できるでしょう。今後試してみたいと思います。