OpenCVの使い方24 ~ 輪郭抽出
今回はOpenCVを用いて画像の輪郭を抽出する方法について紹介したい。
1. 画像読み込みとバイナリ画像変換
今回は以下のOpenCVのモノクロロゴ画像を用いて輪郭線を抽出する。
以下のようにGoogle Colabを用いてモノクロ画像をgray
として読み込む。
import cv2 import numpy as np from matplotlib import pyplot as plt from google.colab import files uploaded_file = files.upload() uploaded_file_name = next(iter(uploaded_file)) orig = cv2.imread(uploaded_file_name) src = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB) gray = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)
輪郭抽出処理を行うため、モノクロ画像をcv2.threshold
を用いて255と0のバイナリ画像に変換しthresh
に格納する。
ret,thresh = cv2.threshold(gray,127,255,0) plt.imshow(thresh,cmap='gray')
もともと単純な画像なので、バイナリ画像に変換しても元の画像とあまり変化はない。
2. 輪郭抽出
バイナリ画像から輪郭線を抽出するにはcv2.findContours
を使用する。引数はバイナリ画像、輪郭検出方法、輪郭近似方法を指定し、出力は検出した輪郭(リスト)と輪郭の階層情報となる。具体的には以下のようにして、contours
に輪郭をリストとして格納する。
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
輪郭検出方法は次の4種類:cv2.RETR_EXTERNAL,
cv2.RETR_LIST
, cv2.RETR_CCOMP
, cv2.RETR_TREE
が指定できるが、今回はcv2.RETR_TREE
を用いる。
また輪郭近似方法はすべての輪郭点を格納するcv2.CHAIN_APPROX_NONE
と水平・垂直・斜めの線分を圧縮し,それらの端点のみを残すcv2.CHAIN_APPROX_SIMPLE
があるがcv2.CHAIN_APPROX_SIMPLE
を使用する。
3. 抽出した輪郭の描画
抽出した輪郭を描画するには、cv2.drawContours
を使用する。元のバイナリ画像と同サイズの配列(ゼロ行列)を用意しcnt_img
とする。
cv2.drawContours
の引数は、配列、検出輪郭リスト、輪郭リストの番号、輪郭を描画する色、輪郭線の太さを指定する。
輪郭リストの番号は-1とするとすべての輪郭が描画される。またモノクロ画像であれば描画する色は255
とすると白線になる。カラーの場合はRGBを(0,255,0)のように指定する。
cnt_img = np.zeros_like(thresh, dtype=np.uint8) cnt_img = cv2.drawContours(cnt_img, contours, -1, 255, 2) plt.imshow(cnt_img,cmap='gray')
以下OpenCVの輪郭が抽出できていることがわかる。
輪郭リストの番号を1つ指定すると、それに対応した輪郭線のみが描画される。例えば輪郭リストを2
と指定するとe
の内側のみの輪郭が描画される。
cnt_img = np.zeros_like(thresh, dtype=np.uint8) cnt_img = cv2.drawContours(cnt_img, contours,2, 255, 2) plt.imshow(cnt_img,cmap='gray')
抽出された輪郭の数を調べるにはlen()
を用いてリストの長さを取得することで得られる。今回は12個の輪郭が抽出されていることがわかる。
n=len(contours) n >12
輪郭リストの各番号がどの輪郭に対応しているか、繰り返し処理を行って表示させることができる。 サブプロットの各タイトルにリストの番号を示すようにしている。
plt.figure(figsize=(12,12)) for i in np.arange(n): cnt_img = np.zeros_like(thresh, dtype=np.uint8) cnt_img = cv2.drawContours(cnt_img, contours,i, 255, 2) plt.subplot(3,4,i+1) plt.imshow(cnt_img,cmap='gray') plt.title('Cont Num'+str(i))
4. まとめ
今回はOpenCVによるモノクロ画像の輪郭の抽出と描画する方法について紹介した。