直線検知のアルゴリズム
Pythonで画像内の直線検知を行うアルゴリズムを書く。(2019年)
直線検知の主なアルゴリズム
- Hough変換
- LSD(Line Segment Detector)
- Pylsd
- OpenCV
※OpenCV3.4.4ではLSDはあるが、4.1.0からは削除されている。
代わりにFastLineDetectorというものがあるが、まだ試していない。(2019年9月18日現在)
各アルゴリズムの中身
ハフ変換
簡単に言うと多数決で直線を検出する方法
画像上のすべての点に対してその点を通る直線を検出し、直線を表すパラメータ群を輝度値で重み付けしていく。
重み付けされた直線を画像に書いていくと、直線が多く通る部分が濃くなり、直線だとわかる。
画像引用 amos storkey
LSD
輝度勾配とLevel Lineの角度を計算する。
輝度勾配は明るさに勾配を表し、LevelLineは異なる領域と分けられる線分を示す。
LevelLineのと勾配によって以下のような図を作成し、領域の推定を行う。
その後、領域を矩形に近似することで直線を検出する。
画像引用
メリット、デメリット
-
Hough変換
- メリット
- 固定の形式であればパラメータにより最適化できる。
- デメリット
- パラメータ探索をグリッドサーチしないと行けないので時間がかかる。
- 探索精度は高いが演算不可が高い。(低いHoughLinePというものもあるが精度が下がる。)
- メリット
-
LSD(LineSegmentDetetor)
- メリット
- パラメータの設定が不要
- デメリット
- パラメータの設定が出来ない分、入力画像の前処理を行ったりして精度を上げないといけない(?) ※検証中
- メリット
所感
Hough変換よりもLSDでの直線検知の方が使いやすくて、精度も高い気がする。
LSDはOpenCVで実装されていたが権利周りで違反していたようで削除された。
代わりにFastLineDetector
が実装されている。(OpenCV==4.1.0)
Pylsd
というものもあるので検証を行ってみて精度の高い方を使用したほうがいい気がした。
使い方
import cv2
src = 'hoge.png' #入力画像のパス
img = cv2.imread(src)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_bitwise = cv2.bitwise_not(gray)
lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=80, maxLineGap=5) #全探索
# lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=80, maxLineGap=5) #確率的探索
for line in lines:
x1, y1, x2, y2 = line[0]
# draw line
lines_img = cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
cv2.imwrite('lined_hoge.png', lines_img)
import cv2
src = 'hoge.png' #入力画像のパス
img = cv2.imread(src)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
mono, th2 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
LSD = cv2.createLineSegmentDetector()
lines, width, prec, nfa = LSD.detect(src)
lines = lines.tolist()
for idx,l in enumerate(lines):
x1,y1,x2,y2 = l[0][0],l[0][1],l[0][2],l[0][3]
# draw line
lines_img = cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
cv2.imwrite('lined_hoge.png', lines_img)
Pylsdを使用する際はインストールに注意が必要そう。
python3に対応させるには以下の方法でインストール
pip install 'ocrd-fork-pylsd == 0.0.3'
参考:pythonの直線検出は間違いなくOpenCVではなくPylsdが優れている
from pylsd.lsd import lsd
src = 'hoge.png' #入力画像のパス
img = cv2.imread(src)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# gray = cv2.GaussianBlur(gray,(5,5),5) # ガウシアンフィルタを使用した方が良いらしい
linesL = lsd(gray)
for line in linesL:
x1, y1, x2, y2 = map(int,line[:4])
lines_img = cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
cv2.imwrite('lined_hoge.png', lines_img)