Posted at

画像から輪郭を抽出して重ね合わせる

More than 1 year has passed since last update.

画像から輪郭を抽出して重ね合わせる方法についてメモ

※opencv-python 3.4にて動作確認済み


サンプル画像

昔非常にお世話になったこの画像に今回もお世話になります。

入力画像
a.jpg

グレースケール
b.jpg

dilate⇒diff
c.jpg

二値化
d.jpg

重ね合わせ
e.jpg


ソースコード

import cv2

def edgeDetect(color):

# カーネルサイズの設定
kernel5 = np.ones((5, 5), np.uint8)
# [1] 画像のグレースケール化とノイズ除去
gray = cv2.fastNlMeansDenoising(
cv2.cvtColor(color, cv2.COLOR_BGR2GRAY), h=20)
# [2] dilate -> diff で線抽出
dilation = cv2.dilate(gray, kernel5, iterations=1)
diff = cv2.subtract(dilation, gray)
diff_inv = 255 - diff
# [3] 線を単色 -> 2値に
_, edge = cv2.threshold(diff_inv, 225, 255, cv2.THRESH_BINARY)
# [4] 線画とモノクロ2値を重ねる
edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
img = cv2.bitwise_and(color, edge)

return img


各工程の解説


[1] 画像のグレースケール化とノイズ除去

輪郭抽出するためにまず画像をグレースケール化する。ついでにcv2.fastNlMeansDenoising()を使用してノイズを除去することでゴミを輪郭として残さないようにする。ノイズの除去量はhを増やせば増えるが、やりすぎに注意。

fastNlMeansDenoisingの詳細

https://docs.opencv.org/3.0-beta/modules/photo/doc/denoising.html#fastnlmeansdenoising


[2] dilate -> diff で線抽出

cv2.dilate()cv2.subtract()を使うと輪郭がいい感じに抽出できる。最後に255 - diffで白黒反転している。


[3] 線を単色 -> 2値に

cv2.threshold()で抽出した線を二値化する。

thresholdの詳細

https://docs.opencv.org/3.0-beta/modules/imgproc/doc/miscellaneous_transformations.html#threshold


[4] 線画とモノクロ2値を重ねる

最後に抽出した輪郭をカラー画像に重ね合わせる。ただし、輪郭はグレースケール画像なのでcv2.cvtColor()を忘れないようにする。

以上