KURORO BLOGのロゴ

このエントリーをはてなブックマークに追加
OpenCVで使われるdrawContoursって?具体的な活用法を徹底解説!?

OpenCVで使われるdrawContoursって?具体的な活用法を徹底解説!?

今回はOpenCVで使われるdrawContours関数に関して、具体的な活用法を徹底解説いたします。なんとなくdrawContours関数を使っていた、画像処理の理解を深めたい方へおすすめです。ぜひ最後までご一読ください。

目次
  1. そもそもOpenCVで使われるdrawContoursとは?
  2. 【5ステップ】drawCountours関数を用いて輪郭を描画してみる
    1. 画像を読み込む
    2. しきい値を用いて二値画像へ変更する
    3. findContours関数を用いて輪郭の検出を行う
    4. 3の輪郭の検出情報をもとに、輪郭を描画する
    5. 画像を保存する
    6. 完成コード
  3. まとめ
  4. 参考文献
目次を開く⬇︎

そもそもOpenCVで使われるdrawContoursとは?

OpenCVで使われるdrawContoursとは、画像に対して輪郭を描画するための関数を意味します。

輪郭を具体的な画像を用いて説明すると、

上記画像の水色の画素(点)=輪郭になります。

輪郭 : 同じ色や値を持つ画素(点)をつなげて、形成される曲線

【5ステップ】drawCountours関数を用いて輪郭を描画してみる

drawCountours関数を用いて輪郭を描画するためには、

  1. 画像を読み込む
  2. しきい値を用いて二値画像へ変更する
  3. findContours関数を用いて輪郭の検出を行う
  4. 3の輪郭の検出情報をもとに、輪郭を描画する
  5. 画像を保存する

を行う必要があります。順に確認していきましょう。

画像を読み込む

始めに画像の読み込みを行います。

1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
4# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
5# 第一引数 : 画像のファイルパス
6# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
7img = cv2.imread('./xxx.xxx')

imreadに関しては、OpenCVで使われるimreadとは?使い方から配列が画像になる仕組みを解説でまとめていますので、詳しく知りたい方は是非ご確認ください。

しきい値を用いて二値画像へ変更する

輪郭を描画するためには、画素(点)を輪郭にすべきか判定できるように、加工しておく必要があります。

画素(点)を輪郭にすべきか決める値 = しきい値を用意して、画像を二値画像へ加工します。

「画像を読み込む」で紹介したコード内のimg = cv2.imread('./xxx.xxx')の下へ以下のコードを貼り付けてください。

1# cvtColor : 画像の色空間(色)の変更を行う関数。
2# cvtColorについて : https://kuroro.blog/python/7IFCPLA4DzV8nUTchKsb/
3# 第一引数 : 多次元配列(numpy.ndarray)
4# 第二引数 : 変更前の画像の色空間(色)と、変更後の画像の色空間(色)を示す定数を設定。
5# cv2.COLOR_BGR2GRAY : BGR(Blue, Green, Red)形式の色空間(色)を持つ画像をグレースケール画像へ変更する。
6# グレースケールとは? : https://www.shinkohsha.co.jp/blog/monochrome-shirokuro-grayscale/
7# 戻り値 : 多次元配列(numpy.ndarray)
8imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
9
10# threshold : しきい値を用いて画像を二値画像へ変更する関数。
11# thresholdについて : https://kuroro.blog/python/jofbNumJ9HtfTxnM8QHJ/
12# 第一引数 : 多次元配列(numpy.ndarray)
13# 第二引数 : しきい値
14# 第三引数 : しきい値を超えた画素(点)に対して、色の値を指定。255(白色)とする。
15# 第四引数 : 二値画像を判定する条件のタイプを設定する。
16# cv2.THRESH_BINARY : (画素(点)の値 <= 第二引数)の場合、画素(点)に対して、0(黒色)の値を与える。(画素(点)の値 > 第二引数)の場合、画素(点)に対して、第三引数の値(白色)を与える。
17# 戻り値 #################
18# ret :  しきい値を返す。
19# thresh : 多次元配列(numpy.ndarray)
20########################
21ret, thresh = cv2.threshold(imgGray, 127, 255, cv2.THRESH_BINARY)

二値画像へ加工することで、2つの色のみで画像が形成されることになり、輪郭の描画を容易にします。

cvtColorに関しては、OpenCVで使われるcvtcolorとは?cvtcolorの活用例を徹底紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。

thresholdに関しては、OpenCVで使われるthresholdとは?threshold活用例を徹底解説でまとめていますので、詳しく知りたい方は是非ご確認ください。

findContours関数を用いて輪郭の検出を行う

findContours関数を用いて、輪郭を形成する画素(点)の検出を行います。

「しきい値を用いて二値画像へ変更する」で紹介したコード内のret, thresh = cv2.threshold(imgGray, 127, 255, cv2.THRESH_BINARY)の下へ以下のコードを貼り付けてください。

1# findContours : 輪郭の検出を行う関数
2# findContoursについて : https://kuroro.blog/python/nSvll3vvUPah6Et2rJqG/
3# 第一引数 : 二値画像情報
4# 第二引数 : 輪郭を検出するタイプを指定する。
5# cv2.RETR_EXTERNAL : 一番外側の輪郭のみ抽出する。
6# 第三引数 : 輪郭を形成する、画素(点)を近似する方法のタイプを指定する。##############
7# cv2.CHAIN_APPROX_SIMPLE : 冗長な画素(点)の情報を削除し、メモリの使用を抑えて輪郭の検出を行う。
8# cv2.CHAIN_APPROX_NONE : 全画素(点)の情報を利用し、輪郭の検出を行う。画素数が多い場合に、メモリの使用量が大きくなり、重くなるので注意が必要。
9###############################################
10# 戻り値  ####################### 
11# image : 輪郭付き画像情報
12# contours : 輪郭を形成する画素(点)情報
13# hierarchy : オブジェクト(物体)の階層構造情報
14###############################
15
16# OpenCVのバージョンが4.0より小さい場合
17image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
18
19# OpenCVのバージョンが4.0以上の場合 
20contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

またPythonを実行してこのようなエラーが発生した場合は、

1Traceback (most recent call last):
2File "/Users/xxx/Desktop/xxx.py", line 9, in <module>
3image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
4ValueError: not enough values to unpack (expected 3, got 2)

以下の手順を踏まえて、OpenCVのバージョンを確認し、

  1. ターミナルを起動する。
  2. python -iを実行(Pythonをインタラクティブモードで実行する。ターミナルから対話型でPythonを実行できる。)
  3. import cv2を実行(cv2(OpenCV)を読み込む。)
  4. print(cv2.__version__)を実行する。(cv2(OpenCV)のバージョンをprint文を用いて確認する。)
  5. quit()(インタラクティブモードを終了する。)

findContours関数の戻り値の数を合わせるように、変更ください。

findContours関数に関しては、OpenCVで使われるfindContoursとは?利用する注意点などを解説でまとめておりますので、是非ご確認ください。

3の輪郭の検出情報をもとに、輪郭を描画する

3の輪郭の検出情報をもとに、輪郭を描画を行います。

「findContours関数を用いて輪郭の検出を行う」で紹介したコード内のimage, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) or contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)の下へ以下のコードを貼り付けてください。

1# drawContours : 輪郭の検出情報をもとに、輪郭の描画を行う関数
2# 第一引数 : 多次元配列(numpy.ndarray)
3# 第二引数 : 輪郭を形成する画素(点)情報
4# 第三引数 : 輪郭を形成する画素(点)のインデックス番号を指定する。例えば0を指定すると、1番目の輪郭を形成する画素(点)のみを描画する。1を指定すると、2番目の輪郭を形成する画素(点)のみを描画する。輪郭を形成する画素(点)を全て描画したい場合は、-1を指定する。
5# 第四引数 : 輪郭を形成する画素(点)の色。BGR(Blue, Green, Red)指定。
6# 第五引数(任意) : 輪郭を形成する画素(点)の大きさを設定。デフォルト1。
7# 戻り値 : 多次元配列(numpy.ndarray)
8output = cv2.drawContours(img, contours, -1, (255, 255, 0), 5)

画像を保存する

最後に画像の保存を行います。

「3の輪郭の検出情報をもとに、輪郭を描画する」で紹介したコード内のoutput = cv2.drawContours(img, contours, -1, (255, 255, 0), 5)の下へ以下のコードを貼り付けてください。

1# imwrite : 画像の保存を行う関数
2# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
3# 第一引数 : 保存先の画像ファイル名
4# 第二引数 : 多次元配列(numpy.ndarray)
5cv2.imwrite('./output.png', output)

imwriteに関しては、OpenCVで使われるimwriteとは?imwriteの定義から使用例をご紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。

実際に紹介したコードを、組み合わせて実行すると、以下の画像ように輪郭が描画されます。

完成コード

1# 1. 画像を読み込む
2# cv2(OpenCV)を利用する宣言を行う。
3import cv2
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread('./xxx.xxx')
10
11# 2. しきい値を用いて二値画像へ変更する
12
13# cvtColor : 画像の色空間(色)の変更を行う関数。
14# cvtColorについて : https://kuroro.blog/python/7IFCPLA4DzV8nUTchKsb/
15# 第一引数 : 多次元配列(numpy.ndarray)
16# 第二引数 : 変更前の画像の色空間(色)と、変更後の画像の色空間(色)を示す定数を設定。
17# cv2.COLOR_BGR2GRAY : BGR(Blue, Green, Red)形式の色空間(色)を持つ画像をグレースケール画像へ変更する。
18# グレースケールとは? : https://www.shinkohsha.co.jp/blog/monochrome-shirokuro-grayscale/
19# 戻り値 : 多次元配列(numpy.ndarray)
20imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
21
22# threshold : しきい値を用いて画像を二値画像へ変更する関数。
23# thresholdについて : https://kuroro.blog/python/jofbNumJ9HtfTxnM8QHJ/
24# 第一引数 : 多次元配列(numpy.ndarray)
25# 第二引数 : しきい値
26# 第三引数 : しきい値を超えた画素(点)に対して、色の値を指定。255(白色)とする。
27# 第四引数 : 二値画像を判定する条件のタイプを設定する。
28# cv2.THRESH_BINARY : (画素(点)の値 <= 第二引数)の場合、画素(点)に対して、0(黒色)の値を与える。(画素(点)の値 > 第二引数)の場合、画素(点)に対して、第三引数の値(白色)を与える。
29# 戻り値 #################
30# ret :  しきい値を返す。
31# thresh : 多次元配列(numpy.ndarray)
32########################
33ret, thresh = cv2.threshold(imgGray, 127, 255, cv2.THRESH_BINARY)
34
35# 3. findContours関数を用いて輪郭の検出を行う
36# findContours : 輪郭の検出を行う関数
37# findContoursについて : https://kuroro.blog/python/nSvll3vvUPah6Et2rJqG/
38# 第一引数 : 二値画像情報
39# 第二引数 : 輪郭を検出するタイプを指定する。
40# cv2.RETR_EXTERNAL : 一番外側の輪郭のみ抽出する。
41# 第三引数 : 輪郭を形成する、画素(点)を近似する方法のタイプを指定する。##############
42# cv2.CHAIN_APPROX_SIMPLE : 冗長な画素(点)の情報を削除し、メモリの使用を抑えて輪郭の検出を行う。
43# cv2.CHAIN_APPROX_NONE : 全画素(点)の情報を利用し、輪郭の検出を行う。画素数が多い場合に、メモリの使用量が大きくなり、重くなるので注意が必要。
44###############################################
45# 戻り値  ####################### 
46# image : 輪郭付き画像情報
47# contours : 輪郭を形成する画素(点)情報
48# hierarchy : オブジェクト(物体)の階層構造情報
49###############################
50# OpenCVのバージョンが4.0より小さい場合
51# image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
52
53# OpenCVのバージョンが4.0以上の場合
54contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
55
56# 4. 3の輪郭の検出情報をもとに、輪郭を描画する
57# drawContours : 輪郭の検出情報をもとに、輪郭の描画を行う関数
58# 第一引数 : 多次元配列(numpy.ndarray)
59# 第二引数 : 輪郭を形成する画素(点)情報
60# 第三引数 : 輪郭を形成する画素(点)のインデックス番号を指定する。例えば0を指定すると、1番目の輪郭を形成する画素(点)のみを描画する。1を指定すると、2番目の輪郭を形成する画素(点)のみを描画する。輪郭を形成する画素(点)を全て描画したい場合は、-1を指定する。
61# 第四引数 : 輪郭を形成する画素(点)の色。BGR(Blue, Green, Red)指定。
62# 第五引数(任意) : 輪郭を形成する画素(点)の大きさを設定。デフォルト1。
63# 戻り値 : 多次元配列(numpy.ndarray)
64output = cv2.drawContours(img, contours, -1, (255, 255, 0), 5)
65
66# 5. 画像を保存する
67# imwrite : 画像の保存を行う関数
68# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
69# 第一引数 : 保存先の画像ファイル名
70# 第二引数 : 多次元配列(numpy.ndarray)
71cv2.imwrite('./output.png', output)

まとめ

  • OpenCVで使われるdrawContoursとは、画像に対して輪郭を描画するための関数として利用する。
  • 輪郭を形成するために、しきい値を用いて二値画像へ加工する必要がある。

参考文献