HoughLinesP の 引数 感度分析【 Python OpenCV 】
画像処理ライブラリの OpenCV ( Python ) の中で線を取得する HoughLinesP があります。一つのコマンドで複数の 引数 を使って意図した線を取得するのですが、画像の状態や大きさ、内容によって変わるみたいです。今回はサンプル画像に対して各引数をふってみた結果をまとめたいと思います。
ライブラリ説明概要
lines = cv2.HoughLinesP(img, rho, theta, threshold, minLineLength, maxLineGap)
一つの関数で線を取得することができます。
ただ、6つの引数があり、それぞれ動きを理解しなければ意図した線を取得することは難しいんです。私自身もはまりました。
1.img
判断する画像データです。白黒の2値画像である必要がありますので、グレースケールなどで変換すれば問題ないでしょう。
2.rho
ピクセル単位で表される投票空間の距離分解能・・・さっぱりです。
3.theta
ピクセル単位で表される投票空間の角度分解能・・・うーん。
何で難しい表現になるのでしょうか?
4.threshold
閾値。なんの?・・・一言でいえば、線とみなすためのメインとなる基準かな?
5.minLineLength
これは読んで字のごとく、最小線長さを指すようです。
6.maxLineGap
これも読んで字のごとく、ギャップ(差)をどこまで一直線としてみなすかの閾値。
6つ引数がありますが、ネットで調べてみた結果をみても・・・よくわかりません。
とりあえず引数を振ってみて動きを理解しつつ、解釈してみました。実践あるのみですね。
サンプル画像は以下を使います。(サイズ → 横:313px 縦:132px)
目的は表の架線を取得することをイメージしてください。
まずは 3. theta をふってみた
簡単そうなものから。ベースとなるコマンドは以下です。
cv2.HoughLinesP
(img, rho=1, theta=**, threshold=1, minLineLength=10, maxLineGap=0)
theta=10
theta=45
theta=90
theta=180
theta=360
thetaを振ってみると、画像の中の線を網羅的に線を取得できる動きのイメージですね。
ただ、統一性(一貫性)があまりありませんね。
でも、思ったように線を取得できていないですね。同じような長さでも線として認識していない様子ですし、文字の直線部を線として認識してしまっています。
つづいて、4. threshold をふってみます。
閾値とは何の閾値なのでしょうか?ベースとなるコマンドは以下です。
cv2.HoughLinesP
(img, rho=1, theta=10, threshold=**, minLineLength=10, maxLineGap=0)
threshold=1
threshold=10
threshold=100
画像の中で線と判断するための閾値のようです。値を大きくすると文字を除外しているイメージですね。threshold=1000とすると線を認識しなくなりましたので、大きければよいというわけではなさそうです。ちょっと目的の架線取得に近づきましたね。
次は、5. minLineLength と 6. maxLineGap を比較してみた
なんとなく引数的にわかりやすそうなので、並べて変化をみてみたいと思います。
cv2.HoughLinesP
(img, rho=1, theta=360, threshold=100, minLineLength=**, maxLineGap=**)
minLength=10,maxgGap=0
minLength=100,maxgGap=0
minLength=10,maxgGap=1
minLength=100,maxgGap=1
minLength=10,maxgGap=3
minLength=100,maxgGap=3
minLength=10,maxgGap=5
minLength=100,maxgGap=5
minLength=10,maxgGap=10
minLength=100,maxgGap=10
想像していた通りですね。
minLineLengthは線として認識する長さ。
minLineGapは途切れた線を一つの線として認識する長さ。
のようですね。
minLineLengthが小さく、minLineGapが大きいと文字などのノイズを線として認識する確率があがっていますね。
さて、最後に2. rho について・・・
最後によくわからない引数です。
cv2.HoughLinesP
(img, rho=**, theta=360, threshold=100, minLineLength=10/100, maxLineGap=3)
※わかりやすくするためにminLineLengthも10,100でふってみました。
rho=1,minLength=10
rho=1,minLength=100
rho=5,minLength=10
rho=5,minLength=100
rho=10,minLength=10
rho=10,minLength=100
<線検出せず>
rho=100,minLength=10
rho=100,minLength=100
<線検出せず>
rho=1000,minLength=10
rho=1000,minLength=100
<線検出せず>
うーん。よくわかりません。
rhoを増やすと、文字など区別せず、線として認識してしまっていますね。
引数をふって何かわかると思ったのですが、よくわからない結果となりました。
継続して調査進めますが、少なくともデフォルトで、rho=1としておけば、線は認識できそうですね。
要約すると・・・
- img:取り込む画像。
- rho:よくわかりませんが、デフォルト 1 で問題なさそう。
- theta:ランダムに線を判断するための回転角。大きくすれば複雑な線を認識する。
- threshold:文字などの非線を除外する閾値(の様なもの)
- minLineLength:連なる点の集合の、最小値。この値以上を線としてみなす。
- maxLineGap:どれだけ離れている点(線)を一つの線としてみなすか判断。
いかがでしょうか?
実際やりたいことはそれぞれですが、どの引数を調整すればイメージつかんでもらえたのではないでしょうか?
実際の線を取得する場合のサンプルソースを以下に紹介していますのでよければどうぞ。
画像 から 線 取得してみた!【 Python OpenCV 】
[https://way2se.ringtrees.com/py_cv2-001/]
画像 から 縦線 のみ取得してみた!【 Python OpenCV 】
[https://way2se.ringtrees.com/py_cv2-002/]
画像 から 横線 のみ取得してみた!【 Python OpenCV 】
[https://way2se.ringtrees.com/py_cv2-003/]