Local Binary Patternの理論と実装


# テクスチャの認識

次の問題どのように解きますか？
<img width="80%" alt="スクリーンショット 2018-10-05 13.01.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/1c7f0143-1bcc-d91f-7717-55a2f8cf538b.png">
もちろん人間が見れば④番だというのはすぐにわかりますが、AI(プログラム)を使ってやろうとすると少し考える必要があります。いろいろなやり方はあるかと思いますが、軽量で低コストなLocalBinaryPatternを使ったやり方を紹介します。

# Local Binary Patternとは

1994年にフィンランドにあるオウル大学のT.Ojalaさん達によって提案[^LBP]された特徴量です。LocalBinaryPattern（LBP）はその名前のとおり、画像の局所的な表現を特徴量としたもので、各画素を周囲の近傍画素と比較した相対値で構成されています。演算コストが低くて、画像の濃淡値の変動に強いといった特徴があり、1994年の最初の提案以降もいろいろな改良が加えられています。特に非ディープラーニング系では、顔画像認識や画像検索やテクスチャ分割、および動画像解析など幅広く使用されています。

# LBP特徴量の求め方

LBP特徴量を画像から抽出するための手順を説明します。
まずはバイナリ化です。画像をグレースケール化して、その画像の各ピクセルについて中心ピクセルを囲む８近傍を選択します。
<img width="80%" alt="スクリーンショット 2018-10-03 18.28.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/41ebf2c2-51b5-621d-ad91-66bfac235ed7.png">
中心のピクセル（56のピクセル）を取り、それをその近傍8ピクセルに対して閾値として設定します。 中心ピクセルの値より隣接ピクセルの値の方が大きいか等しい場合1に、小さい場合は0に設定します。
<img width="80%" alt="スクリーンショット 2018-10-03 18.32.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/cef96cc5-53f5-ce43-22bc-cbb98dee11ec.png">

次に、LBP値を計算します。真ん中上の点から反時計回りに２進数として解釈して、それを10進数に直します。この例では49になります。
<img width="80%" alt="スクリーンショット 2018-10-03 18.36.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/e7cd511e-632c-079b-d09c-bae105866ce8.png">

これを入力画像の全てのピクセルに対して行うので、計算されたLBP値は、元の画像と同じ幅と高さの出力配列として得られます。
<img width="80%" alt="スクリーンショット 2018-10-03 18.38.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/72094f8d-fef5-a554-3183-63f5b67a77b8.png">

LBP値は最小値が０で最大値が255になるので、グレースケールの画像として可視化する事もできます。下の図は、画像をLBP値にしてグレースケール化したものになります。
<img width="80%" alt="スクリーンショット 2018-10-03 18.47.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/b333c332-3d2b-df37-abe0-e6b10806b4f2.png">
また、LBP値は中心値と周辺値との大小比較でしかないため、原理的に濃淡に対して不変性が保たれます。下の例は入力画像の露出値を変更して暗くしたものです。それに対してLBP値のグレースケール画像の方はほとんど変化してないのがわかるかと思います。
<img width="80%" alt="スクリーンショット 2018-10-03 18.52.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/5cbb1771-6d7d-7274-92c4-ae981ac9218d.png">

最後に、LBP値を特徴量として扱いやすくするためにヒストグラム化します。LBP値は0〜255の256段階あるので、各値の出現頻度を256binのヒストグラムとして構築する事ができます。

<img width="60%" alt="スクリーンショット 2018-10-03 19.01.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/e3541bab-cde2-b7d9-a5c4-1225e36fd00e.png">

このヒストグラムを正規化すれば、256次元で長さ1の特徴ベクトルとして扱うことができます。

# Uniform LBP

ここまでの説明では、3x3の画像範囲で256段階固定となっていましたが、もっと柔軟に画像パターンを捉えることができるように、これらの値をパラメータ化する拡張が提案[^TO_PARAM]されました。パラメータは次の２つです。

- パラメータ $P$: 円形で対称な近傍の点の数
- パラメータ $R$: 円の半径

<img width="80%" alt="スクリーンショット 2018-10-03 19.25.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/61425963-cf74-5175-c798-25f06491dc8e.png">

また、回転すると一致するパターンは１つに集約し、画像の回転に対してもロバストになる改良も加えられました。下の例[^TUTORIAL]では、8つのマスクパターンを最も左のLBP値15に集約しています。

<img width="1068" alt="スクリーンショット 2018-10-03 19.39.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/5daa6f7d-dabe-b6a0-7439-7947ac78c4e1.png">

さらに、回転させたら同じ形となるパターンのうち、意味をなすもの同士を集約するために、Uniformパターンという考え方が導入されました。下の図[^TUTORIAL]は円を順番になぞっていった場合の 0 → 1 もしくは、1 → 0 の遷移回数毎にまとめたものです。$U=0$は遷移回数０回、$U=2$は遷移回数２回となります。このように$U$の値ごとにパターンをまとめ、$U=0$もしくは$U=2$となるのものをUniformパターン、それ以外のものを non-uniformパターンと定義します。
<img width="80%" alt="スクリーンショット 2018-10-04 10.57.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/0991fd31-cd0d-25f5-5f1d-918f19c7578f.png">

$P=8$で考えた場合、Uniformパターンとなるものは全部で58種類あり、そのうち回転して同じとなるものを同一パターンに集約すればUniformパターンは下の図[^TUTORIAL]のように９種類に分けられます。non-uniformパターンを全てまとめて１種類に集約すれば、全てのパターンは１０種類のいずれかに分類できることになります。
<img width="80%" alt="スクリーンショット 2018-10-04 10.57.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/6fb72a93-34c9-fdf5-792e-d4a6aab01cb8.png">
この例のように$P=8$の場合は１０種類となりますが、この種類数は$P$にのみ依存するので、**点の数が$P$の場合$(P+2)$種類に分類できる**というように一般化することができます。

Uniformパターンは点の数によって種類が分けられますが、それぞれのUniformパターンは画像内の特定の箇所でよく出現することがわかっています。例えば$P=8$の場合は下図[^TUTORIAL]のようになります。
<img width="80%" alt="スクリーンショット 2018-10-04 10.58.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/6af09526-3947-db99-5936-5efd6692448a.png">
次の図[^SCIKIT]はタイルの画像をUniformLBPにして、そのパターン出現頻度をヒストグラム化したものです。ヒストグラムの赤色の部分は画像の赤色の部分で検出されています。Uniformパターン毎に画像内の違う特定の箇所で検出されているというのがよくわかるかと思います。
<img width="90%" alt="スクリーンショット 2018-10-04 10.58.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/e49adfb5-0fe7-60cb-5bff-40e9abee909d.png">


# LBPの実装

実際にLBPを利用するには、pipでscikit-imageをインストールすればOKで、LBP値を取得する部分は一行で書くことができます。次のコードは$P=22$、$R=9$でUniformLBPを取得してヒストグラム化する例になります。

```python:create_lbp_feature.py

import cv2
from skimage import feature
from matplotlib import pyplot as plt

file_name = './tex/sample1.jpg'
bgr_img = cv2.imread(file_name)
gray_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2GRAY)

points = 22
radius = 9

# compute the Local Binary Pattern representation of the image
lbp = feature.local_binary_pattern(gray_img, points, radius, method='uniform')

plt.hist(lbp.ravel(), bins=points + 2, range=(0, points + 2), color='red')
plt.show()
```

このコードを実行した結果、下記のヒストグラムが出力されます。
<img width="1053" alt="スクリーンショット 2018-10-04 10.59.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/5f888845-4eb3-6938-4c28-d8bd8faa51f8.png">

# LBPの実験

６つの写真を使って実験してみます。
同じ種類のテクスチャを２枚ずつ合計６つの異なる写真に対して、UniformLBPで(non-uniformパターンを除いて)ヒストグラムにした結果になります。

<img width="100%" alt="スクリーンショット 2018-10-04 10.59.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/146511/56b6fc05-f027-6c2b-0bea-969a46d5e744.png">

結果のヒストグラムを見ると、同じ種類のテクスチャはヒストグラムの形が似ているのがわかると思います。ヒストグラムを特徴ベクトルにして、例えばcos類似度などで比較すれば簡単に同じオブジェクトを見つける事ができるかと思います。


[^LBP]: Ojala T, Pietikäinen M & Harwood D, “Performance evaluation of texture measures with classification based on Kullback discrimination of distributions.”, Proc. 12th International Conference on Pattern Recognition (ICPR 1994), Jerusalem, Israel. Vol I, 582-585. (1994)

[^TO_PARAM]: Ojala T, Pietikäinen M & Mäenpää T (2002) Multiresolution gray-scale and rotation invariant texture classification with Local Binary Patterns. IEEE Transactions on Pattern Analysis and Machine Intelligence 24(7):971-987.

[^TUTORIAL]: http://www.ee.oulu.fi/research/imag/mvg/files/pdf/CVPR-tutorial-final.pdf

[^SCIKIT]: http://scikit-image.org/docs/dev/auto_examples/features_detection/plot_local_binary_pattern.html