すだちキャンパス

すだちキャンパス

やってみたこと、学んだことなどのメモ。

Pythonで画像処理〜モルフォロジー変換〜

こんにちは。Pythonで画像処理シリーズです。
今回はモルフォロジー変換という操作を行って、画像の中の星の数を数えるという事をしました。

前回の記事はこちら↓
kabos.hatenablog.jp

モルフォロジー変換とは

画像の特定の場所を膨張させたり収縮させたりすることでノイズを除去することのようです。膨張や収縮といった操作は、カーネルを作りたたみ込み演算を行うことでできます。
それでは、実際に画像を処理していきます。

準備

まずは画像を読み込んでグレースケールに変換し、正規化します。

img = plt.imread('stars.jpg')
img = np.mean(img, 2)
img /= np.max(img)

f:id:sweetgohan:20191209065359j:plain
オリジナル画像
元画像はこんな感じです、月と星が写っています。

次に、閾値を決めて画像をバイナリ化します。

threshold = 0.2
img_thr = img > threshold

f:id:sweetgohan:20191211205324p:plain

モルフォロジー変換

クロージング

それでは変換を行なっていきます。まずはクロージングと呼ばれる、膨張させてから収縮させる操作を行います。これは穴を埋めるようにノイズを除去する作業らしいです。

#カーネルを定める
kernel_closing = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
#クロージング
img_thr_cl = nd.binary_closing(img_thr, structure=kernel_closing)

f:id:sweetgohan:20191211205452p:plain

オープニング

次に、オープニングというクロージングとは逆の作業を行います。オープニングは、孤立した(余分な)点を除去する作業に対応するようです。

#カーネルを定める
kernel_opening = np.array([[0, 0, 0], [0, 1, 1], [0, 0, 0]])
#オープニング
img_thr_cl_op = nd.binary_opening(img_thr_cl, structure=kernel_opening)

f:id:sweetgohan:20191211205525p:plain

ファインチューニング

最後に、nd.binary_dilationという関数を使って画質をよくします。

kernel3 = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
img_final = nd.binary_dilation(img_thr_cl_op, structure=kernel3)

f:id:sweetgohan:20191211205940p:plain

ここまでできたら、星がノイズと間違われて消されていないか、またノイズが星として誤認識されていないかを確認してみます。~はビット反転の演算子です。

opts = dict(cmap='gray', vmin=0.)
f, [ax1, ax2, ax3] = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(10,5))
ax1.imshow(~img_thr_cl_op * img, vmax=1., **opts)

ax2.imshow(img_thr_cl_op, vmax=.1, **opts)

ax3.imshow(img, vmax=.1, **opts)

f:id:sweetgohan:20191211210125p:plain

星の個数を数える

最後に星の個数を数えます。

slice_list = nd.find_objects(img_final)

ここで、scipy.ndimage.find_objectsは星がどこにあるかを返す関数です。例えば今回だと最初の返り値は

(slice(24, 30, None), slice(946, 951, None))

なのですが、これはつまり

img_final[24:30, 946:951]

のことを表しています。

そして各星の大きさをまとめて、ヒストグラムで表示します。

#星のリスト
star_list = [img[slc] for slc in slice_list]
#大きさのリスト
mass_list = [np.sum(star) for star in star_list]
#小さい順に並べる
mass_list_sorted = sorted(mass_list)
#一番大きい星(月)を削除
mass_list_sorted.pop(-1)
mass_list_without_moon = mass_list_sorted
#ヒストグラム
plt.hist(mass_list_without_moon, bins=100)

f:id:sweetgohan:20191211215350p:plain