Python
 Computer >> コンピューター >  >> プログラミング >> Python

PythonとOpenCVで画像から直線を検出する方法|ハフ変換を徹底解説

この記事では、「ハフ変換」と呼ばれる手法を使って、画像内の直線を検出する方法を解説します。

ハフ変換とは?

ハフ変換は、数学的な形式で表現できる「単純な形状」を検出するための特徴抽出手法です。多少途切れていたり歪んでいたりしても、その形状を検出できる点が大きな特徴です。ここでは、直線の場合にどのように機能するのかを見ていきます。

ここでいう「単純」な形状とは、少数のパラメータだけで表現できる形状のことです。例えば、直線は傾きと切片の2つのパラメータだけで表現でき、円は中心座標と半径の3つのパラメータ(x, y, r)で表現できます。

ハフ変換による画像からの直線検出

直線は方程式で表現できます。パラメトリック形式では、ρ(ロー)を原点から直線までの垂直距離、θ(シータ)をこの垂線と水平軸がなす角度(反時計回りに測定。OpenCVではこの表現が採用されています)として表されます。下の図をご覧ください。

PythonとOpenCVで画像から直線を検出する方法|ハフ変換を徹底解説

直線が原点より下側を通る場合、ρは正の値となり、角度は180度未満になります。一方、原点より上側を通る場合は、180度を超える角度を使う代わりに180度未満の角度を採用し、ρは負の値となります。また、垂直線は常に0度、水平線は90度になります。

アキュムレータ(投票器)の仕組み

あらゆる直線は(ρ, θ)という2つのパラメータで表現できます。そこでまず、これら2つのパラメータの値を保持するための2次元配列(アキュムレータ)を作成し、初期値をすべて0に設定します。行がρ、列がθを表します。配列のサイズは必要な精度によって決まります。例えば、角度の精度を1度にしたい場合は180列が必要です。ρについては、最大距離は画像の対角線の長さになるため、1ピクセル単位の精度とすれば、行数は画像の対角線の長さとなります。

ここで、中央に水平線が引かれた100×100の画像を例に考えてみましょう。まず直線上の最初の点を取り、その座標(x, y)がわかっているとします。次に、式にθ=0, 1, 2, 3…180の値を順番に代入し、それぞれ得られるρの値を計算します。そして、各(ρ, θ)ペアに対応するアキュムレータのセルの値を1ずつ増やします。この時点で、アキュムレータのセル(50, 90)=1となり、他のいくつかのセルにも同様に値が入ります。

続いて、直線上の2番目の点を取り、最初の点と同じ手順を繰り返します。得られた(ρ, θ)に対応するセルの値を増加させると、今度はセル(50, 90)=2になります。つまり、実際には(ρ, θ)の値に対して「投票」を行っているのです。このプロセスを直線上のすべての点に対して繰り返します。各点ごとにセル(50, 90)は投票され続けますが、他のセルはほとんど投票されません。こうして最終的に、セル(50, 90)が最大票数を持つことになります。

したがって、アキュムレータ内で最大票数を検索すれば、値(50, 90)が得られます。これは「原点から距離50、角度90度の位置に直線が存在する」ことを意味します。これが直線検出におけるハフ変換の基本的な仕組みです。

OpenCVでのハフ変換

上記で説明した一連の処理は、すべてOpenCVの関数cv2.HoughLines()に実装されています。この関数は、ρがピクセル単位、θがラジアン単位で測定された(ρ, θ)値の配列を返します。

以下は、OpenCVとハフ直線変換を使用して直線を検出するプログラムです。サンプルでは、確率的ハフ変換であるcv2.HoughLinesP()を使用しています。

下の画像は実際の駐車場の写真です。この画像に対して、ハフ直線変換とOpenCVライブラリを使って直線検出を行います。

PythonとOpenCVで画像から直線を検出する方法|ハフ変換を徹底解説

サンプルコード

import cv2
import numpy as np
img = cv2.imread("parkingLot1.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 75, 150)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, maxLineGap=250)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 128), 1)
cv2.imshow("linesEdges", edges)
cv2.imshow("linesDetected", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

主な引数の説明:

  • edges:Canny法などで生成した入力エッジ画像
  • 1:ρの分解能(ピクセル単位)
  • np.pi/180:θの分解能(ラジアン単位・1度刻み)
  • 30:直線とみなすために必要な最小投票数(閾値)
  • maxLineGap=250:同一の直線として扱う点間の最大ギャップ

実行結果

Canny法によるエッジ検出の結果:

PythonとOpenCVで画像から直線を検出する方法|ハフ変換を徹底解説

そして、検出された直線:

PythonとOpenCVで画像から直線を検出する方法|ハフ変換を徹底解説

  1. PythonのOpenCVモジュールで画像に幾何学図形を描画する方法

    はじめに OpenCVの基本操作のひとつが「画像への描画」です。線、円、矩形(長方形)など、さまざまな幾何学形状を画像上に追加できます。 画像解析の現場では、画像の一部を強調表示したい場面がよくあります。たとえば、注目したい領域を囲む矩形を追加したり、特定の場所を指し示す矢印を描いたりするケースです。本記事では、PythonのOpenCVモジュールを使って画像に幾何学図形を描画する方法を、サンプルコードとともにわかりやすく解説します。 主な描画関数一覧 cv2.line() … 画像に直線を描画する関数 cv2.rectangle() … 画像に矩形を描画する関数 cv2.circle()

  2. PythonとOpenCVを使って動画を逆再生(リバース再生)する方法

    OpenCVは「Open Source Computer Vision(オープンソース・コンピュータビジョン)」の略称です。この強力なライブラリを活用することで、画像や動画に対してさまざまな操作を実行できます。OpenCVの主な応用分野顔認識システムモーショントラッキング(動体追跡)人工ニューラルネットワーク深層ニューラルネットワーク動画ストリーミング などOpenCVのインストール方法Windows環境では、以下のコマンドでインストールできます。pip install opencv-pythonLinux環境の場合は、次のコマンドを使用します。sudo apt-get install pyt