OpenCVのfindContours関数を使った画像の輪郭検出

概要

OpenCVのfindContours関数は、画像から輪郭(またはエッジ)を検出するための機能で、物体認識、形状分析、物体追跡などの前段階のタスクでよく使用されています。 出力は、検出された各輪郭は点のリストと、輪郭の階層情報(各輪郭が他の輪郭の内側にあるか、外側にあるか)を返します。輪郭は画像上の点の連続した曲線として表現され、各輪郭は点のシーケンスとして保存されます。下記では、findContours関数の使用方法とその解説を画像処理入門向けに解説いたしますので、是非ご活用ください。

出力結果

サンプル画像
輪郭検出した画像
OpenCVのfindContours関数を使った画像の輪郭検出

プログラム全体

#解説1 import cv2 import numpy as np import matplotlib.pyplot as plt from skimage import io #解説2 # サンプル画像のURL url = 'https://upload.wikimedia.org/wikipedia/commons/5/53/OpenCV_Logo_with_text.png' # 画像読み込む img = io.imread(url) #解説3 # グレースケールに変換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二値化(閾値を150に設定) ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) #解説4 # 輪郭を検出 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #解説5 # 全て白の画像を作成 img_blank = np.ones_like(img) * 255 # 輪郭だけを描画(黒色で描画) img_contour_only = cv2.drawContours(img_blank, contours, -1, (0,0,0), 3) # 描画 plt.imshow(cv2.cvtColor(img_contour_only, cv2.COLOR_BGR2RGB)) plt.show()

解説

解説1:ライブラリのインポート

import cv2 import numpy as np import matplotlib.pyplot as plt from urllib.request import urlopen from skimage import io

この部分では、プログラムで使用するライブラリをインポートしています。ライブラリとは、特定の機能をまとめたプログラムの集合で、これをインポートすることでその機能を簡単に利用することができます。下記にインポートするライブラリについて説明しています。

cv2 OpenCVという画像処理ライブラリ。画像の読み込み、色空間の変換、二値化、輪郭検出など、画像処理に必要な機能を提供しています。
numpy 数値計算を効率的に行うためのライブラリ。画像データは数値の配列として扱うことが多いため、このライブラリが必要です。
matplotlib.pyplot グラフ描画や画像表示のためのライブラリ。
urllib.request.urlopen URLを開くための関数。このプログラムでは使用していません。
skimage.io scikit-imageという画像処理ライブラリの一部。URLから直接画像を読み込む機能があります。下記のコマンドでインストールできます。
pip install scikit-image

補足:matplotlibとは?

Pythonおよびその科学計算用ライブラリNumPyのためのグラフ描画ライブラリで、要は数学データの可視化(グラフ描写)を簡単に行うためのライブラリです。様々な種類のグラフに対応しているので使い方を覚えておくととても便利です。以下のコマンドでインストールできます。

pip install matplotlib

解説2:画像の読み込み

# サンプル画像のURL url = 'https://upload.wikimedia.org/wikipedia/commons/5/53/OpenCV_Logo_with_text.png' # 画像読み込む img = io.imread(url)

この部分では、サンプル画像をインターネットから読み込んでいます。

url 画像のURLを指定します。このURLの画像を読み込みます。
io.imread(url) URLから画像を読み込む関数。読み込んだ画像データはimgに保存されます。

解説3:画像の前処理

# グレースケールに変換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二値化(閾値を150に設定) ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)

この部分では、画像の前処理を行っています。具体的には、画像をグレースケールに変換し、二値化しています。

cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 画像をグレースケールに変換する関数。グレースケール画像は色情報を持たず、明暗だけで情報を表現します。これにより、画像データの量を減らし、処理を簡単にします。
cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) この部分では、cv2.thresholdを使って画像に閾値処理を適用しています。閾値処理とは、画像の各ピクセルに対して、その値がある閾値より大きければ一定の値(ここでは255、つまり白)に、それ以外なら別の値(ここでは0、つまり黒)に変換する処理です。このプログラムでは"150"を閾値に設定しているのでこれを境に白と黒に別れる事になります。

解説4:輪郭の検出

# 輪郭を検出 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

この部分では、二値化した画像から輪郭を検出しています。

cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 二値化画像から輪郭を検出する関数。この関数は、白い部分(値が255の部分)の輪郭を検出します。輪郭は黒い背景から白いオブジェクトを分離するためのツールとして使用されます。

補足:findContoursの引数について

findContours関数で取得できる情報は、輪郭を構成している点の座標軍と輪郭の内側の情報です。下記の関数の引数を変更することで、輪郭検出の挙動を細かく制御することができます。具体的には、輪郭の階層構造の取得方法や輪郭の近似方法を変更することができます。引数を変えることによって、メモリ使用量を抑えたり取得したい部分をピンポイントで抜き出すことができます。

第1引数 binary 輪郭抽出する画像データ(二値化したデータを使用します。二値化されていない場合は、輝度値が0で無い部分に関しての輪郭情報を取得します。)
第2引数 cv2.RETR_TREE 輪郭構造の取得方法(輪郭の階層情報の取得方法を下記の中から指定します。)
RETR_TREE 輪郭の階層情報をツリー形式で取得します。
RETR_CCOMP 白の輪郭と黒の輪郭の情報だけを取得します。
RETR_LIST 白、黒の区別なく、すべての輪郭を同じ階層として取得します。
RETR_EXTERNAL 一番外側の白の輪郭だけを取得します。
第3引数 cv2.CHAIN_APPROX_SIMPLE 輪郭座標の取得方法(輪郭を構成する点の座標の取得方法を下記の中から指定します。)
CHAIN_APPROX_NONE 輪郭上のすべての座標を取得。
CHAIN_APPROX_SIMPLE 縦、横、斜め45°方向に完全に直線の部分の輪郭の点を省略。
CHAIN_APPROX_TC89_L1,
CHAIN_APPROX_TC89_KCOS
輪郭の座標を直線で近似できる部分の輪郭の点を省略します。

解説5:輪郭の描画と表示

# 全て白の画像を作成 img_blank = np.ones_like(img) * 255 # 輪郭だけを描画(黒色で描画) img_contour_only = cv2.drawContours(img_blank, contours, -1, (0,0,0), 3) # 描画 plt.imshow(cv2.cvtColor(img_contour_only, cv2.COLOR_BGR2RGB)) plt.show()
np.ones_like(img) * 255 全てのピクセルが白色(255)の画像を作成します。この画像のサイズは元の画像と同じです。
cv2.drawContours(img_blank, contours, -1, (0,0,0), 3) 白色の画像上に輪郭を黒色で描画します。この関数は、指定した画像上に輪郭を描画します。
plt.imshow(cv2.cvtColor(img_contour_only, cv2.COLOR_BGR2RGB))plt.show() matplotlibを使用して画像を表示します。cv2.cvtColor(img_contour_only, cv2.COLOR_BGR2RGB)は、OpenCVがBGR形式で画像を扱うのに対して、matplotlibはRGB形式で画像を扱うため、色空間の変換を行っています。

おまけ

画像処理を行う際、特にカメラを用いて取得する画像の品質は重要な要素となります。高品質でクリアな画像が入力されることで、より精度の高い画像処理が可能となります。産業用カメラは高解像度のRAW画像を取得することができ、これによりエッジが際立つモノクロ画像を生成することが可能です。TheImagingSource社のカメラSDKとOpenCVの画像処理機能を組み合わせることで、下記のように鮮明な画像の取得とリアルタイムの画像処理を同時に行うことができます。
https://www.argocorp.com/software/sdk/ICImagingControl/Sample_program/Python_34/callback.html