OpenCVで画像から輪郭検出の基本(findContours関数あたり)

2019年8月30日

またOpenCV実験です。今度は画像から何らかの物体を検出してみます。ここではfindCoutours関数で、物体の輪郭(領域、contour)を検出するための基本を実験してみたいと思います。

環境はざっくりいうとUbuntu18.04にOpenCVバージョン4で検証しています。

このあたりを参考にしています。

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html

まずやってみることとしては、Pixabayから拝借してきたクラゲの画像からクラゲを抽出して囲って見たいと思います。

クラゲオリジナル画像

ポイントとしては以下2点なんだと思います。

・OpenCVでcv2.findCountoursに画像を渡す際に画像は背景が黒、抽出したい物体は白になっている画像に変換してやる。

・グレースケールから白黒はっきりさせるためにcv2.threshold 関数をうまく設定する必要がある。

こちらサンプルコードです。UbuntuDesktop環境で実施です。

import numpy as np
import cv2

#カラー画像を読み込んでグレースケール値に変換。
img=cv2.imread('jfcolor.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#threshholdを使って白黒のエリアを決定する。
ret,thresh = cv2.threshold(gray,63,255,cv2.THRESH_BINARY)
cv2.imshow('thresh',thresh)

#輪郭を検出。
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#輪郭を書き込み。
contimg=cv2.drawContours(img,contours,-1,(0,255,0),3)

#最終表示
cv2.imshow('final',contimg)
cv2.waitKey(0)
cv2.destroyAllWindows()

以下解説です。

1.画像ファイルをグレスケール読み込み

cv2.findCountoursに白黒画像を渡すためにまずはカラー画像を読み込んでグレースケール変換です。画像ファイル名は’jfcolor.jpg’です。当然はじめからグレースケールで読み込んでもよいですが、最後にカラー画像をまた使いますので、別々の処理です。

img=cv2.imread('jfcolor.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

2.cv2.threshholdを使って白黒のエリアを決定する。

ret,thresh = cv2.threshold(gray,63,255,cv2.THRESH_BINARY)

ここでは2番目の引数threshを変更すると色々白黒の領域が変わることがわかります。

オリジナルグレースケール

クラゲ画像グレースケール

・thresh=31の時

クラゲ画像グレースケールthresh=31時

・thresh=63の時

クラゲ画像グレースケールthresh=63時

・thresh=127の時

クラゲ画像グレースケールthresh=127時

とthresh値により白黒の領域が変わってくるとがわかるのではと思います。thresh値が小さいほど白い領域が多くなるということみたいですね。

3.cv2.threshholdを使った白黒はっきりさせた画像から輪郭を取得

contours,hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

2,3番目にはいろいろな値が設定できますが、今回はまずcv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLEにしておきます。contoursには複数の領域が入っています。hierarchyは領域の内側に更に領域があった場合などで使えるようですが、いったんおいておきます。

4.輪郭の書き込み

contimg=cv2.drawContours(img,contours,-1,(0,255,0),3)

輪郭はいろいろかけると思いますが、一番単純に拾った輪郭を全部書き込んでみます。

クラゲ画像クラゲ検出

多少いらない輪郭も拾っていますが、これだけの短いコードでここまでできてしまうのはすごいですね。

いったんここまでにさせていただきます。


OpenCV

Posted by kitakantech