python

画像処理・解析その3

直線・円の検出方法

直線は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)