#はじめに
某KEY***E社の画像検査装置などにはトレンドエッジと
いうエッジを回帰直線として検出する機能があったりします。
OpenCVでもエッジを近似した直線として扱いたい。
#課題
画像中エッジの回帰直線を求めてみます。
##サンプル画像
画像は作成。ノイズは標準偏差2.0で発生。
#手順
・2値化
・Cannyエッジ検出実行後に画像の端に余計なエッジが出てしまうので、
それを避けるため、画像端より2画素をマージンとし、その内側を処理対象とします。
・Cannyエッジ検出を実施、エッジ座標を回帰分析します。
・回帰分析については、他に多数説明するWebページがございますので
そちらを参照下さい。
・直線式
上記式の回帰分析を行い、a傾き, b切片を求めます。
numpyのpolyfit()で回帰計算をします。これについても他に
多数説明があるため、そちらを参照して下さい。
#実行環境
・Python 3.7.3 Anaconda
・OpenCV 3.4.1
・numpy 1.16.3
#コード
import cv2
import numpy as np
def main():
# 入力画像の読み込み
img = cv2.imread("images/test_hline4_sd2.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, bin0 = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)
height = img.shape[0]
width = img.shape[1]
# エッジ画像取得
edgcanny = cv2.Canny(bin0,50,100)
edgimg = np.zeros(bin0.shape, dtype=np.uint8)
sp = 2
edgimg[sp:height-sp,sp:width-sp] = edgcanny[sp:height-sp,sp:width-sp]
#cv2.imwrite('images/edgcanny.png', edgcanny)
#cv2.imwrite('images/edgimg.png', edgimg)
# 白色位置の座標を抽出
yl, xl = np.where(edgimg == 255)
# 回帰計算
p = np.poly1d(np.polyfit(xl,yl,1))
#print(p)
# 結果描画
resimg = cv2.cvtColor(bin0, cv2.COLOR_GRAY2BGR)
# 回帰直線を描画
x1 = 0
y1 = int(p(x1))
x2 = width-1
y2 = int(p(x2))
cv2.line(resimg, (x1, y1), (x2, y2), (0,0,255), 1, lineType=cv2.LINE_AA)
cv2.imwrite('images/resimg.png', resimg)
# 結果表示
cv2.imshow('Image', resimg)
cv2.waitKey(0)
if __name__ == '__main__':
main()
#結果
直線式 y = -0.09705 x + 58.86
いい感じ。
#おわりに
エッジなどを回帰計算で扱うことは一般的だと思っていたのですが、
そうでもないようで、他にこんなことを書いているページも
見つけられなかったので書いて見ました。
ちなみに、KEY***E社のは、エッジ部分をセグメントで分けて、セグメント区間内で
平均的エッジ位置を求め、セグメント単位で計算して回帰直線を求めているようです。
おそらく処理を安定化させるためでしょう。