blog

HOG特徴記述演算子 - 歩行者検出

このタスクでは、ディープラーニングで非常に人気のある画像特徴抽出技術、Histogram of Orientation Gradients、略してHOG特徴を学習します。HOG特徴は、2005年のCV...

Oct 4, 2020 · 4 min. read
シェア

入門

このタスクでは、ディープラーニングで非常にポピュラーなイメージ特徴抽出技術であるHistogram of Orientation Gradients、略してHOG特徴を学習します。HOG特徴は2005年にCVPRのカンファレンスで発表され、当時歩行者検出の分野で大きな成功を収めたイメージ手動特徴抽出の画期的な技術です。

HOG特徴量の考え方を学ぶことは、従来のイメージ特徴量の記述やイメージ認識手法をよく理解することにも役立ちます。 このタスクでは、HOGの背後にある設計原理とopencvの実装を学びます。

コンテンツの提示

HOGの特徴の簡単な説明

HOG特徴量はイメージの局所特徴量の一種で、基本的な考え方は、局所イメージの勾配の大きさと方向に関する統計量を投票し、勾配の特徴に基づいてヒストグラムを形成し、局所特徴量をつなぎ合わせて全体特徴量とすることです。この文脈での局所特徴とは、イメージを複数のサブブロック(ブロック)に分割し、各ブロック内の特徴を組み合わせて最終的な特徴を形成することを意味します。

HOG+SVMのワークフローは以下の通りです:まず、入力イメージを前処理し、勾配の大きさと勾配の方向を含むピクセル点の勾配特徴を計算します。次に、投票統計によって勾配ヒストグラムが形成され、ブロックが正規化され、最後にHOG特徴が収集され、教師あり学習のためにSVMに投入されます。上記HOGの主な学習手順は以下の通り。

HOG特徴量の原理

イメージの前処理

前処理にはグレイスケーリングとガンマ変換が含まれます。

グレースケールイメージもカラーイメージもグラデーションマップの計算に使えるので、グレースケール処理はオプションの処理です。カラーイメージの場合、3つのチャンネルの色値それぞれについて勾配を計算し、最も大きな勾配値を持つものをそのピクセルの勾配とします。

その後、ガンマ補正を行い、イメージのコントラストを調整し、イメージへの光の影響を軽減し、露出オーバーまたは露出アンダーのイメージを人間の目で見たイメージに近い正常な状態に戻します。

  • ガンマ補正式.

f(I)=Iγf=Iγf=IγIIはイメージ、γγはパワーインデックスを表します。

図に示すように、γγが異なる値を取る場合の対応する入力曲線と出力曲線: 1)Iγ1の場合、入力イメージの低グレー値領域のダイナミックレンジが大きくなり、イメージの低グレー値領域のコントラストを強調することができます、高グレー値領域では、ダイナミックレンジが小さくなり、イメージの高グレー値領域のコントラストを低減することができます。 最終的に、イメージ全体のグレースケールが明るくなります。

2)γγγ>1 の場合、入力イメージの低グレイ値領域のダイナミックレンジが小さくなり、イメージの低グレイ値領域のコントラストが低下し、高グレイ値領域ではダイナミックレンジが大きくなり、イメージの高グレイ値領域のコントラストが向上します。 最終的に、イメージ全体のグレースケールは暗くなります。

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('E:/python-project/deep-learning/picture/test1.jpg', 0)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img2 = np.power(img/float(np.max(img)),1/2.2)
plt.imshow(img2)
plt.axis('off')
plt.show()

イメージのグラデーションを計算

グラデーションヒストグラムを得るためには、まずイメージの水平方向と垂直方向のグラデーションを計算する必要があります。これは通常、特定の畳み込みカーネルを使ってイメージにフィルタをかけることで実現されます。利用可能な畳み込みテンプレートには、soble演算子、Prewitt演算子、Robertsテンプレートなどがあります。

soble演算子は、OpenCVのように、入力イメージで畳み込まれたsoble水平・垂直演算子を用いてdxdx,dydyを計算するために一般的に使用されます:

\text {Sobel}_{X}=\left[\begin{array}{c} 1 \\\ 0 \\\ -1 \end{array} ight] *\left[\begin{array}{ccc} 1 & 2 & 1 \end{array} ight] =\left[\begin{array}{ccc} 1 & 2 & 1 ¦ 0 & 0 & 0 ¦ -1 & -2 & -1 ¦ end{array} ¦rightleft[\begin{array}{ccc} 1 & 0 & -1 ⊖end{array}right]=left[⊖begin{array}{ccc} 1 & 0 & -1 ⊖2 & 0 & -2 ⊖1 & 0 & -1 ⊖end{array}right] ⊖d_x}=f(x, y)^{*}.\operatorname{Sobel}_{x} \\\ d_{y}=f(x, y)^{*} \operatorname{Sobel}_{y} \end{array}$$ The magnitude of the image gradient can be further obtained: $M(x, y)=\sqrt{d_{x}^{2}+d_{y}^{2}}$.M(x, y)=left|d_{x}right|+left|d_{y}right|$ 角度は次の通り: $theta_{M}=arctan \left(d_{y} / d_{x}right)$ ここで注意すべきことは、勾配とエッジ方向は直交することです。方向は互いに直交。![ここにイメージの説明を挿入) ``` python import cv2 import numpy as np # イメージの読み込み img = cv2.imread('E:/python-project/deep-learning/picture/test1.jpg') img = np.float32(img) / 255.0 # 正規化されます. # x 方向と y 方向のグラデーションを求めます.angle = cv2.cartToPolar(gx, gy, angleInDegrees=True) ``` **グラデーションヒストグラムの計算** 前段階の後,各ピクセル点は,グラデーションの大きさとグラデーションの方向の2つの値を持ちます.例えば,イメージが64x128のサイズにリサイズされた場合,イメージは8x16の8x8セル単位に分割され,各8x8セルに対してグラデーションヒストグラムが計算されます.もちろん、セルの分割は、特定のシーンに応じて、16x16、8x16など、他の値でもかまいません。勾配ヒストグラムを計算する際、なぜイメージをいくつものセルに分割するのかをまず理解しましょう。 これは、勾配マップ全体をピクセルごとに計算すると、その中の有効な特徴が非常に疎になり、計算量が大きくなるだけでなく、ノイズの干渉を受けるからです。そこで、よりコンパクトな特徴を表現するために局所特徴記述子を用い、そのような局所セル上で勾配ヒストグラムを計算する方がよりロバストです。例として、8x8のセルは、各ピクセルが勾配の大きさと方向を含むので、8x8x2=128個の値を含みます。HOGでは、各8x8セルの勾配ヒストグラムは、基本的に0、20、40、60...160の勾配方向に対応する9つの値のベクトルです。つまり、元のセルの8x8x2=128個の値は、長さ9のベクトルで表現されます。このように勾配ヒストグラムを表現することで、計算量が大幅に削減されると同時に、照明などの環境の変化にも強くなります。まず、次のイメージを見てください![左のイメージは64x128のドレスのイメージで、8x16 8x8のセルに分割されています。真ん中のイメージはセル内のグラデーションベクトル、矢印の方向はグラデーションの方向、矢印の長さはグラデーションの大きさを表しています。右のイメージは、8x8セル内のグラデーションの生の値です。 角度が0度から360度ではなく、0度から180度の範囲であることに注意してください。これは、2つの全く反対の方向が同じであるとみなされるため、「符号なし」グラデーションとして知られています。次に、セル内のピクセルのグラデーションのヒストグラムを、0度から180度の範囲を9つのビンと呼ばれる0、20、40...160.そして各ビンの勾配の寄与がカウントされます![ここにイメージの説明を挿入]統計的な方法は、上の図に示すように、ピクセルの勾配の大きさは13.6、方向は36、ビンの角度の両側に36度が20度と40度であった重み付け投票統計であり、その後、20度と40度に対応するビンの一定の加重割合によると、勾配の値に追加されました、重み付けの式:ビンに対応する40度:* 13.6、分母の20度に対応するビン:* 13.6、分母の20は20度ではなく20等分という意味です。もう一つ注意すべき点があり、あるピクセルの勾配角度が160度より大きい場合、つまり160度から180度の間にある場合、このピクセルの勾配値は左図のように0度と160度に対応するビンに比例して分割されます。下の緑の円の角度は165度で、大きさは85度です。この場合、85は同じ重み付け方法で0度と160度に対応するビンに加えられます。![イメージの説明をここに挿入] HOG特徴記述子でヒストグラムが作成される方法と全く同じように、セル全体についてボーテカウントを行うと、9つの値からなるベクトル勾配方向プロットが得られます: ![ブロック正規化** HOG特徴は、8×8の局所領域をセルとして扱い、2×2のセルのグループをブロックとして扱います。なぜブロックを分割する必要があるのか不思議に思われるかもしれません。なぜなら、HOG特徴はイメージの8×8セルに対して作成されていますが、イメージの勾配は全体の照明に敏感だからです。つまり、あるイメージに対して、ある部分は他の部分に比べて非常に明るくなります。これをイメージから完全に取り除くことはできません。しかし、16×16のブロックを使ってグラデーションを正規化することで、この照明のばらつきを減らすことができます。各セルは9個の値を持ち、1ブロックは36個の値を持つので、HOGはスライディングウィンドウを使ってブロックを取得します。先に説明したように、正規化の目的は照明の影響を減らすことです。勾配は照明全体の影響を非常に受けやすいため、例えば、すべてのピクセル値を2で割ってイメージを暗くした場合、勾配の大きさは半分になり、したがってヒストグラムの値も半分になるため、ヒストグラムを「正規化」する必要があります。ヒストグラムを正規化するには、L1ノルム、L2ノルム、max/minなどいろいろな方法があります。 例えば、[128, 64, 32]の3Dベクトルについて、モジュラスは $sqrt{128^2+64^2+32^2}=146.64$ となり、これはベクトルのL2ノルムと呼ばれます。このベクトルの各要素を 146.64 で割ると、正規化されたベクトル [0.87, 0.43, 0.22] が得られます。同じ方法で、1つのセルは9つの値を含む勾配方向ヒストグラムを持ち、1つのブロックは4つのセルを持ち、1つのブロックは4つの勾配方向ヒストグラムを持ち、これら4つのヒストグラムをつなぎ合わせて長さ36のベクトルを形成し、このベクトルを正規化します。そして,各ブロックは,ブロックのイメージ全体が計算されるまで,上記のスライドと同じ方法で繰り返されます.**HOGディスクリプタの取得** サイズ16 * 16の各ブロックは、長さ36の特徴ベクトルを取得し、正規化されます。 では、いくつの特徴ベクトルが得られるでしょうか?例えば、上の図が8 * 16のセルに分割され、各ブロックが2x2のセルを持つとすると、セルの数は、x(8-1)=105、つまり、横7個、縦15個のブロックがあります。 各ブロックは36個の値を持ち、すべてのブロックの固有値を積分することで、36 * 105 = 3780個の固有値からなる特徴記述子が得られます。最終的な結果は、36 * 105 = 3780個の特徴値からなる特徴記述子となり、この特徴記述子は、長さ3780の1次元ベクトルとなります。 HOG特徴ベクトルが得られ、視覚化と分類に使用できます。多次元のHOG特徴については、SVMが有用です。## 4.3 OpenCV ベースの実装 ``python import cv2 as cv import numpy as np from matplotlib import pyplot as plt if __name__ == '__main__': src = cv.imread("E:/python-project/deep-learning/picture/test7.jpg") cv.imshow("input", src) hog = cv.HOGDescriptor() hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector()) # イメージ内の人物の検出 = hog.detectMultiScale(src, winStride=, padding=, scale=1.2, useMeanshiftGrouping=)for in rects: cv.rectangle(src, , , 2) cv.imshow("hog-detector", src) cv.imwrite("hog-detector.jpg",src) cv.waitKey(0) cv.destroyAllWindows() ``` ![ここにイメージの説明を挿入] ![ここにイメージの説明を挿入] は,あまりうまく動作しません.変更してください.[ここにイメージの説明を挿入] ![ここにイメージの説明を挿入] 可視化: ``` python from skimage import feature, exposure from matplotlib import pyplot as plt import cv2 image = cv2.imread('E:/python-project/deep-learning/picture/test8.jpg') image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) fd, hog_image = feature.hog(image, orientations=9fd, hog_image = feature.hog(image, orientations=9, pixels_per_cell=, cells_per_block=, visualise=True) # 表示を良くするためにヒストグラムを再スケーリング hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=) cv2.namedWindow("img",cv2.WINDOW_NORMAL) cv2.imshow('img', image) cv2.namedWindow("hog",cv2.WINDOW_NORMAL) cv2.imshow('hog', hog_image_rescaled) cv2.waitKey(0)==ord('q') ``` ![ここにイメージの説明を挿入] ## 4.4まとめ HOGアルゴリズムには以下の利点があります: - HOGはエッジ構造特徴を記述するため,物体の構造情報を記述することができる - 照明の影響を受けにくい - チャンキングによって,よりコンパクトな特徴表現が可能 HOGアルゴリズムには以下の欠点があります: - 特徴記述子の取得処理が複雑で,次元が高いため,リアルタイム性能が低い - オクルージョン問題の扱いが難しい- ノイズの影響を受けやすい 論文アドレス:[Histograms of Oriented Gradients for Human Detection - 2005CVPR].
Read next

ES6 varとlet、const

varとlet、constの使い方を理解する上で、まずいくつかの概念を知っておく必要があります:スコープ 1.グローバルスコープ:ウィンドウ、一般的にはコードのブロックにラップされた<script>タグによってラップされる 2.関数スコープ:コードのブロックの関数によってラップされる 3.ブロックレベルスコープ:{}のペアでラップされる

Oct 3, 2020 · 4 min read