OpenCV 5.0.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 5.0.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
ハフ直線変換

前のチュートリアル: Cannyエッジ検出器
次のチュートリアル: ハフ円変換

原著者Ana Huamán
互換性OpenCV >= 3.0

目的

このチュートリアルでは、以下の方法を学ぶ:

  • OpenCVの関数 HoughLines()HoughLinesP() を使って画像中の直線を検出する。

理論

覚え書き
以下の説明は、BradskiとKaehlerによる書籍 Learning OpenCV に基づくものである。

ハフ直線変換

  1. ハフ変換による直線検出は、直線を検出するために用いられる変換である。
  2. この変換を適用するには、まず前処理としてエッジ検出を行うことが望ましい。

どのように動作するか?

  1. As you know, a line in the image space can be expressed with two variables. For example:
    1. 直交座標系において: 引数: \((m,b)\)。
    2. 極座標系において: 引数: \((r,\theta)\)

ハフ変換では、直線を極座標系で表現する。したがって、直線の方程式は次のように書ける:

\[y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right )\]

項を整理すると: \(r = x \cos \theta + y \sin \theta\)

  1. 一般に、各点 \((x_{0}, y_{0})\) について、その点を通る直線の集合を次のように定義できる:

    \[r_{\theta} = x_{0} \cdot \cos \theta + y_{0} \cdot \sin \theta\]

    これは、各組 \((r_{\theta},\theta)\) が \((x_{0}, y_{0})\) を通る各直線を表すことを意味する。

  2. ある \((x_{0}, y_{0})\) についてそこを通る直線の集合をプロットすると、正弦曲線が得られる。たとえば \(x_{0} = 8\)、\(y_{0} = 6\) の場合、次のようなプロット(\(\theta\) - \(r\) 平面上)が得られる:

ここでは \(r > 0\) かつ \(0< \theta < 2 \pi\) を満たす点のみを考える。

  1. 画像中のすべての点に対して上記と同じ操作を行うことができる。2つの異なる点の曲線が \(\theta\) - \(r\) 平面上で交差する場合、その両点は同じ直線上にあることを意味する。たとえば、上記の例に続けて、さらに2つの点 \(x_{1} = 4\)、\(y_{1} = 9\) と \(x_{2} = 12\)、\(y_{2} = 3\) のプロットを描くと、次のようになる:

3つのプロットは1つの点 \((0.925, 9.6)\) で交差する。これらの座標は、\((x_{0}, y_{0})\)、\((x_{1}, y_{1})\)、\((x_{2}, y_{2})\) が乗る直線の引数( \(\theta, r\))である。

  1. 上記のすべては何を意味するのか? それは一般に、曲線間の交点の数を求めることによって直線を検出できることを意味する。交差する曲線が多いほど、その交点で表される直線がより多くの点を持つことを意味する。一般に、直線を検出するために必要な交点の最小数のしきい値を定義できる。
  2. これがハフ変換による直線検出の動作である。画像中の各点の曲線間の交点を追跡する。交点の数があるしきい値を超えた場合、その交点の引数 \((\theta, r_{\theta})\) を持つ直線として宣言する。

標準的および確率的ハフ直線変換

OpenCVは3種類のハフ変換による直線検出を実装している:

a. 標準ハフ変換

  • これは前節で説明したものとほぼ同じである。結果として組 \((\theta, r_{\theta})\) のベクトルを返す。
  • OpenCVでは関数 HoughLines() で実装されている。

b. 確率的ハフ変換による直線検出

  • ハフ変換による直線検出のより効率的な実装。検出された直線の端点 \((x_{0}, y_{0}, x_{1}, y_{1})\) を出力として返す。
  • OpenCVでは関数 HoughLinesP() で実装されている。

c. 重み付きハフ変換

  • 標準ハフ変換における2値の0または1の値の代わりに、エッジ強度を用いる。
  • OpenCVでは関数 HoughLines() に use_edgeval=true を指定して実装されている。
  • samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp の例を参照。

このプログラムは何をするか?

  • 画像を読み込む
  • 標準ハフ変換 (Standard Hough Line Transform)確率的ハフ変換 (Probabilistic Line Transform) を適用する。
  • 元画像と検出された線を3つのウィンドウに表示する。

コード

解説

画像を読み込む:

Cannyディテクタを使って画像のエッジを検出する:

ここでハフ変換を適用する。この目的で利用できる2つのOpenCV関数の使い方を説明する。

標準的ハフ直線変換:

まず、変換を適用する:

  • with the following arguments:
    • dst: エッジディテクタの出力。グレースケール画像である必要がある(ただし実際には二値画像である)
    • lines: 検出された線の引数 \((r,\theta)\) を格納するベクトル
    • rho : 引数 \(r\) の分解能(ピクセル単位)。ここでは 1 ピクセルを使う。
    • theta: 引数 \(\theta\) の分解能(ラジアン単位)。ここでは 1 度 (CV_PI/180) を使う
    • threshold: 線を「*検出*」するための交点数の最小値
    • srnstn: デフォルトでは0に設定される引数。詳細はOpenCVリファレンスを参照。

そして線を描画して結果を表示する。

確率的ハフ直線変換

まず、変換を適用する:

  • with the arguments:
    • dst: エッジディテクタの出力。グレースケール画像である必要がある(ただし実際には二値画像である)
    • lines: 検出された線の引数 \((x_{start}, y_{start}, x_{end}, y_{end})\) を格納するベクトル
    • rho : 引数 \(r\) の分解能(ピクセル単位)。ここでは 1 ピクセルを使う。
    • theta: 引数 \(\theta\) の分解能(ラジアン単位)。ここでは 1 度 (CV_PI/180) を使う
    • threshold: 線を「*検出*」するための交点数の最小値
    • minLineLength: 1本の線を構成できる点数の最小値。この点数未満の線は無視される。
    • maxLineGap: 同一の線とみなすための2点間のギャップの最大値。

そして線を描画して結果を表示する。

元の画像と検出された直線を表示する:

ユーザがプログラムを終了するまで待つ

結果

覚え書き
以下の結果は、Codeセクションで述べたもう少し凝ったバージョンを使って得られたものである。上記と同じ処理を実装しており、しきい値用のトラックバーを追加しているだけである。

数独の画像のような入力画像を使う。標準的ハフ直線変換を使うと次の結果が得られる:

確率的ハフ変換を使うと:

threshold を変更すると、検出される線の数が変化することがわかる。その理由は明白である。しきい値を高く設定すると、検出される線は少なくなる(線が検出されたと判定するためにより多くの点が必要になるため)。