直線・円の検出方法
直線は2つのパラメータで決めることができます。
ご存知の通り、下記の式で直線を表します。
y = ax + b => a:傾き、b:切片
ただ、別のパラメータを使用して直線を表す事もできます。
ρ:原点から直線までの距離
θ:x軸から直線までの角度
直線の検出方法
1、画素のある点を探す
原点からx軸方向、y軸方向に対して確認していきます。
2、θを様々な値に設定し、θの値ごとにρを計算
3、全ての点(画素)で1)と2)を繰り返す
4、θとρの出現頻度を集計
5、出現頻度の最も多いものが直線
直線検出後の描画に関しての注意点
θとρが求まってもその情報だけでは描画できません。
ここで必要になってくるのが、検出した直線の始点と終点の座標です。
その座標を求めるには、θとρで表した直線の式を利用します。
1つ注意するのが、θとρで表した直線の式はθ=0のとき発散します。
そこで、下記のようなベクトル表現を用いることになります。
※直線の検出はノイズに弱い
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('Lenna_(test_image).png')
img_o = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_canny = cv2.Canny(img_g, 100, 250)
# 1=>ρの刻み幅、np.pi/180=>θの刻み幅、100=>出現数の閾値
lines = cv2.HoughLines(img_canny, 1, np.pi/180, 100)
for i in lines[:]:
rho = i[0][0]
theta = i[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = rho * a
y0 = rho * b
# 始点
x1 = int(x0 +1000 * (-b))
y1 = int(y0 +1000 * (a))
# 終点
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(img_o, (x1, y1), (x2, y2), (255, 0, 0), 1)
plt.imshow(img_o)
# 円の検出
# パラメータの設定は上手くやらないとノイズだらけになる
circles = cv2.HoughCircles(img_g, cv2.HOUGH_GRADIENT, dp=1, minDist=1, param1=20, param2=35, minRadius=1, maxRadius=30)
# 上手く表示されないことが多いので色々とパラメータ調整の必要あり
# こちらもノイズに弱い
for i in circles[0]:
cv2.circle(img_o, (i[0], i ), i , (255, 0, 0), 1)
plt.imshow(img_o)
モルフォロジー演算
モルフォロジー演算は物の形にまつわる画像処理になります。
具体的には、膨張と収縮からなります。具体的にはピクセルを収縮させたり、膨張させると図形を分離できるという特性を用います。
上記の膨張と収縮を組み合わせた物をオープニング・クロージングと呼びます。
これは、図形の大きさを保ちながら、形状操作するものです。
ここまでの内容をまとめると、モルフォロジー演算を使用することで、分離したり、ノイズを消したりすることができます。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('Lenna_(test_image).png', 0)
# モルフォロジー演算は画像が2値化されている必要がある
ret, img_th = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), dtype=np.uint8)
img_d = cv2.dilate(img_th, kernel)
img_e = cv2.erode(img_th, kernel)
fig = plt.figure(figsize=(15, 9))
plt.gray()
fig.add_subplot(1,3,1)
plt.imshow(img_th)
plt.gray()
fig.add_subplot(1,3,2)
plt.imshow(img_d)
plt.gray()
fig.add_subplot(1,3,3)
plt.imshow(img_e)
# ノイズを消した後に、穴を埋める
img_c = cv2.morphologyEx(img_th, cv2.MORPH_CLOSE, kernel)
fig = plt.figure(figsize=(15, 9))
plt.gray()
fig.add_subplot(1,3,1)
plt.imshow(img_th)
plt.gray()
fig.add_subplot(1,3,2)
plt.imshow(img_d)
plt.gray()
fig.add_subplot(1,3,3)
plt.imshow(img_c)