openCV
前回、openCVで円を検出する方法を紹介しました。
今回は直線を検出する方法を紹介します。
使う画像は前回同様こちらの画像(shapedetection.png)です。
それでは始めていきましょう。
確率的ハフ変換による直線の検出
直線を検出するには標準的ハフ変換という方法と確率的ハフ変換という方法があるようです。
標準的ハフ変換では検出された線は原点から線までの距離ρと線の法線がX軸と成す角のθで表され、無限長の線としての結果が得られるようです。
また確率的ハフ変換では、始点と終点で表された線分として結果が得られます。
ちなみに確率的ハフ変換では画像上の形を点で表し、適当に選んだ点が直線に並んでいたら、その間にも点があると仮定してその点を探し出すことを繰り返し、直線を探し出す手法のようです。
ここらへんの専門的な内容はいろいろなページで解説されているので、そちらにお任せすることにしましょう。
どちらかというと線分を検出する方が多いと思うので、ここでは確率的ハフ変換による直線の検出を試してみます。
確率的ハフ変換は「cv2.HoughLinesP(画像, rho=ピクセルの解像度, theta=角度の解像度, threshold=直線と判断する点の数, minLineLength=検出する最小の長さ, maxLineGap=同じ直線上と解釈するギャップの最大値)」として実行します。
import cv2
import numpy as np
img_gray = cv2.imread("shapedetection.png", cv2.IMREAD_GRAYSCALE)
lines = cv2.HoughLinesP(img_gray, rho=1, theta=np.pi/360, threshold=80, minLineLength=500, maxLineGap=5)
print(lines)
実行結果
[[[ 0 433 599 59]]
[[ 0 431 599 3]]
[[ 0 408 594 0]]
(中略)
[[ 41 439 599 356]]
[[ 55 398 599 10]]
[[ 33 421 599 95]]]
第一の注意点は画像はグレースケール画像を用います。
そして得られる結果は3次元配列となっており、中には線分の始点のX値、Y値、終点のX値、Y値と並んでいます。
これを元の画像に乗せてみましょう。
import cv2
import numpy as np
img_gray = cv2.imread("shapedetection.png", cv2.IMREAD_GRAYSCALE)
lines = cv2.HoughLinesP(img_gray, rho=1, theta=np.pi/360, threshold=80, minLineLength=500, maxLineGap=5)
img = cv2.imread("shapedetection.png")
for line in lines:
x1 = line[0][0]; y1 = line[0][1]
x2 = line[0][2]; y2 = line[0][3]
cv2.line(img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 0, 0), thickness=5, lineType=cv2.LINE_4, shift=0)
cv2.imwrite("line8-1.jpg", img)
実行結果
黒の線が検出された直線ですが、うまく検出できませんでした。
このような場合にはまずはエッジ検出を行ってから、直線検出を行うのが良いようです。
ということでCanny法によるエッジ検出を行ってみます。
import cv2
import numpy as np
img_gray = cv2.imread("shapedetection.png", cv2.IMREAD_GRAYSCALE)
img_canny = cv2.Canny(img_gray, 100, 200)
cv2.imwrite("line8-2.jpg", img_canny)
実行結果
これを用いて確率的ハフ変換による直線検出を試してみます。
import cv2
import numpy as np
img_gray = cv2.imread("shapedetection.png", cv2.IMREAD_GRAYSCALE)
img_canny = cv2.Canny(img_gray, 100, 200)
lines = cv2.HoughLinesP(img_canny, rho=1, theta=np.pi/360, threshold=10, minLineLength=20, maxLineGap=2)
img = cv2.imread("shapedetection.png")
for line in lines:
print(line[0])
x1 = line[0][0]; y1 = line[0][1]
x2 = line[0][2]; y2 = line[0][3]
cv2.line(img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 0, 0), thickness=5, lineType=cv2.LINE_4, shift=0)
cv2.imwrite("line8-3.jpg", img)
実行結果
今回は完璧とまでは言えないまでもかなり良い直線検出ができています。
次回は図形の輪郭を検出する方法を紹介します。
ではでは今回はこんな感じで。
コメント