OpenCVで使われるfindContoursとは?利用する注意点などを解説
今回はOpenCVで使われるfindContoursに関して、利用する注意点から各引数の使い方まで解説いたしました。なんとなくfindContoursを使っていた方へおすすめです。是非最後までご覧ください。
- そもそもOpenCVで使われるfindContoursとは?
- OpenCVで使われるfindContours関数の定義
- findContours関数を用いて輪郭を検出する前に
- findContours関数の第二引数(mode)で指定される、タイプについて調べてみた
- findContours関数の第三引数(method)で指定される、タイプについて調べてみた
- まとめ
- 参考文献
そもそもOpenCVで使われるfindContoursとは?
OpenCVで使われるfindContoursとは、輪郭を検出して、画像内に含まれるオブジェクト(物体)を取得する関数を意味します。
輪郭を具体的な画像を用いて説明すると、
上記画像の灰色の画素(点)=輪郭になります。
輪郭 : 同じ色や値を持つ画素(点)をつなげて、形成される曲線。
OpenCVで使われるfindContours関数の定義
findContours関数は、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# findContours : 輪郭の検出を行う関数
5# 第一引数(thresh) : 二値画像情報
6# 二値画像とは? : https://ja.wikipedia.org/wiki/%E4%BA%8C%E5%80%A4%E7%94%BB%E5%83%8F#:~:text=%E4%BA%8C%E5%80%A4%E7%94%BB%E5%83%8F%EF%BC%88%E3%81%AB%E3%81%A1,%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%80%82
7# 第二引数(mode) : 輪郭を検出するタイプを指定する。
8# 第三引数(method) : 輪郭を形成する、画素(点)を近似する方法のタイプを指定する。
9# 戻り値 #######################
10# image : 輪郭付き画像情報
11# contours : 輪郭を形成する画素(点)情報
12# hierarchy : オブジェクト(物体)の階層構造情報
13# 階層構造とは? : https://wa3.i-3-i.info/word15200.html
14###############################
15
16# OpenCVのバージョンが4.0より小さい場合
17image, contours, hierarchy = cv2.findContours(thresh, mode, method)
18
19# OpenCVのバージョンが4.0以上の場合
20contours, hierarchy = cv2.findContours(thresh, mode, method)
で定義されます。
OpenCVのバージョンにより、findContours関数の戻り値の数に違いがあります。
findContours関数を利用する際は、OpenCVのバージョンを確かめてから利用しましょう。
OpenCVのバージョン確認方法
以下の手順を踏まえて、OpenCVのバージョンを確認し、
- ターミナルを起動する。
python -i
を実行(Pythonをインタラクティブモードで実行する。ターミナルから対話型でPythonを実行できる。)import cv2
を実行(cv2(OpenCV)を読み込む。)print(cv2.__version__)
を実行する。(cv2(OpenCV)のバージョンをprint文を用いて確認する。)quit()
(インタラクティブモードを終了する。)
findContours関数の戻り値の数を合わせるように、変更ください。
findContours関数を用いて輪郭を検出する前に
もしかすると、「findContours関数を利用すれば、どんな画像でも輪郭を検出できる!」と考える方もいるかもしれません。
しかし前処理をして適切な画像を利用しないと、「画像のどの部分を輪郭として検出すべきか」判定できません。
「画像のどの部分を輪郭として検出すべきか」判定できるように、二値画像へ加工する前処理を行う必要があります。
二値画像 : 2色のみで形成される画像。画像の輪郭の検出の際に、前処理として作成される。
二値画像へ加工する方法
二値画像へ加工するためには、
cv2.cvtColor()
を利用して、BGR(Blue, Green, Red)画像をグレースケール画像に変換するcv2.threshold()
を利用して、二値画像を生成する
を行います。
例えば以下のようなコードを作成して、Python環境で実行すると、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4class Paint:
5 # 画像情報
6 img = None
7 # しきい値情報
8 # しきい値とは? : https://wa3.i-3-i.info/word15002.html
9 ret = None
10
11 # コンストラクタ
12 # コンストラクタとは? : https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF#:~:text=%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%EF%BC%88%E8%8B%B1%3A%20constructor%EF%BC%89%E3%81%AF,%E5%AF%BE%E7%BE%A9%E8%AA%9E%E3%81%AF%E3%83%87%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%80%82
13 # 画像の初期化
14 def __init__(self, image=None):
15 self.img = image
16
17 # 画像をグレースケールに設定する関数
18 # グレースケールとは? : https://www.shinkohsha.co.jp/blog/monochrome-shirokuro-grayscale/
19 # 1. cv2.cvtColor()を利用して、BGR(Blue, Green, Red)画像をグレースケール画像に変換する
20 def setGray(self):
21 # cvtColor : 画像の色空間(色)の変更を行う関数。
22 # cvtColorについて : https://kuroro.blog/python/7IFCPLA4DzV8nUTchKsb/
23 # 第一引数 : 多次元配列(numpy.ndarray)
24 # 第二引数 : 変更前の画像の色空間(色)と、変更後の画像の色空間(色)を示す定数を設定。
25 # cv2.COLOR_BGR2GRAY : BGR(Blue, Green, Red)形式の色空間(色)を持つ画像をグレースケール画像へ変更する。
26 self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
27
28 # グレースケール画像を二値画像へ変更する関数
29 # 2. cv2.threshold()を利用して、二値画像を生成する
30 def setBinaryImage(self):
31 # threshold : しきい値を用いて画像を二値画像へ変更する関数。
32 # thresholdについて : https://kuroro.blog/python/jofbNumJ9HtfTxnM8QHJ/
33
34 # 第一引数 : 多次元配列(numpy.ndarray)
35 # 第二引数 : しきい値。float型。
36
37 # 第三引数 : しきい値を超えた画素に対して、255を設定する。しきい値を超えていないものに関しては、0を与える。
38
39 # 第四引数 : 二値画像を判定する条件のタイプを指定する。
40 # cv2.THRESH_BINARY : (画素 <= 第二引数)の場合、画素に対して、0の値を与える。(画素 > 第二引数)の場合、画素に対して、第三引数の値を与える。
41
42 # 戻り値 #################
43 # self.ret : しきい値を返す。
44 # self.img : 多次元配列(numpy.ndarray)を返す。
45 #########################
46 self.ret, self.img = cv2.threshold(self.img, 160, 255, cv2.THRESH_BINARY)
47
48 # 画像を保存する関数
49 def writeImg(self, filePath):
50 # imwrite : 画像の保存を行う関数
51 # imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
52 # 第一引数 : 保存先の画像ファイル名
53 # 第二引数 : 多次元配列(numpy.ndarray)
54 cv2.imwrite(filePath, self.img)
55
56# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
57# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
58# 第一引数 : 画像のファイルパス
59ins = Paint(cv2.imread('./xxx.xxx'))
60ins.setGray()
61ins.setBinaryImage()
62ins.writeImg('./xxx.xxx')
以下の画像のように二値画像を生成できます。
imreadに関しては、OpenCVで使われるimreadとは?使い方から配列が画像になる仕組みを解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
imwriteに関しては、OpenCVで使われるimwriteとは?imwriteの定義から使用例をご紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。
thresholdに関しては、OpenCVで使われるthresholdとは?threshold活用例を徹底解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
cvtColorに関しては、OpenCVで使われるcvtcolorとは?cvtcolorの活用例を徹底紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。
findContours関数の第二引数(mode)で指定される、タイプについて調べてみた
findContours関数の第二引数(mode)では、輪郭を検出するタイプを指定します。
輪郭を検出するタイプとしては、
タイプ名称 | 特徴 |
---|---|
cv2.RETR_EXTERNAL | 最も外側の輪郭のみを抽出します。 |
cv2.RETR_LIST | すべての輪郭を抽出します。一切の階層構造(オブジェクト(物体)の中にオブジェクト(物体)があったとしても、それぞれ独立したオブジェクト(物体)として捉えて、輪郭を形成する)を保持せず、輪郭を形成します。 |
cv2.RETR_CCOMP | すべての輪郭を抽出します。二値(黒と白色)画像の黒色オブジェクト(物体)箇所の輪郭を先に形成して、次に白色オブジェクト(物体)箇所の輪郭を形成します。 |
cv2.RETR_TREE | すべての輪郭を抽出します。階層構造(オブジェクト(物体)の中にオブジェクト(物体)が存在する)になった二値(黒と白色)画像の、外から輪郭を形成します。 |
があります。
例えば以下のようなコードを作成すると、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4class Paint:
5 # 画像情報
6 img = None
7 # しきい値情報
8 # しきい値とは? : https://wa3.i-3-i.info/word15002.html
9 ret = None
10 # 輪郭を形成する画素(点)情報
11 contours = None
12 # オブジェクト(物体)の階層構造情報
13 hierarchy = None
14
15 # コンストラクタ
16 # コンストラクタとは? : https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF#:~:text=%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%EF%BC%88%E8%8B%B1%3A%20constructor%EF%BC%89%E3%81%AF,%E5%AF%BE%E7%BE%A9%E8%AA%9E%E3%81%AF%E3%83%87%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%80%82
17 # 画像の初期化
18 def __init__(self, image=None):
19 self.img = image
20
21 # 画像をグレースケールに設定する関数
22 # グレースケールとは? : https://www.shinkohsha.co.jp/blog/monochrome-shirokuro-grayscale/
23 def setGray(self):
24 # cvtColor : 画像の色空間(色)の変更を行う関数。
25 # cvtColorについて : https://kuroro.blog/python/7IFCPLA4DzV8nUTchKsb/
26 # 第一引数 : 多次元配列(numpy.ndarray)
27 # 第二引数 : 変更前の画像の色空間(色)と、変更後の画像の色空間(色)を示す定数を設定。
28 # cv2.COLOR_BGR2GRAY : BGR(Blue, Green, Red)形式の色空間(色)を持つ画像をグレースケール画像へ変更する。
29 self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
30
31 # グレースケール画像を二値画像へ変更する関数
32 def setBinaryImage(self):
33 # threshold : しきい値を用いて画像を二値画像へ変更する関数。
34 # thresholdについて : https://kuroro.blog/python/jofbNumJ9HtfTxnM8QHJ/
35
36 # 第一引数 : 多次元配列(numpy.ndarray)
37 # 第二引数 : しきい値。float型。
38
39 # 第三引数 : しきい値を超えた画素に対して、255を設定する。しきい値を超えていないものに関しては、0を与える。
40
41 # 第四引数 : 二値画像を判定する条件のタイプを指定する。
42 # cv2.THRESH_BINARY : (画素 <= 第二引数)の場合、画素に対して、0の値を与える。(画素 > 第二引数)の場合、画素に対して、第三引数の値を与える。
43
44 # 戻り値 #################
45 # self.ret : しきい値を返す。
46 # self.img : 多次元配列(numpy.ndarray)を返す。
47 #########################
48 self.ret, self.img = cv2.threshold(self.img, 160, 255, cv2.THRESH_BINARY)
49
50 # 輪郭の検出を行う関数
51 def exeFindContours(self, type):
52 # findContours : 輪郭の検出を行う関数
53 # 第一引数(thresh) : 二値画像情報
54 # 第二引数(mode) : 輪郭を検出するタイプを指定する。
55 # 第三引数(method) : 輪郭を形成する、画素(点)を近似する方法のタイプを指定する。
56 # 戻り値 ###########################################
57 # self.img : 輪郭付き画像情報
58 # self.contours : 輪郭を形成する画素(点)情報
59 # self.hierarchy : オブジェクト(物体)の階層構造情報
60 ####################################################
61
62 # OpenCVのバージョンが4.0より小さい場合
63 # self.img, self.contours, self.hierarchy = cv2.findContours(self.img, type, cv2.CHAIN_APPROX_NONE)
64 # OpenCVのバージョンが4.0以上の場合
65 self.contours, self.hierarchy = cv2.findContours(self.img, type, cv2.CHAIN_APPROX_NONE)
66
67 # 輪郭の描画を行う関数
68 def exeDrawContours(self):
69 # drawContours : 輪郭の検出情報をもとに、輪郭の描画を行う関数
70 # 第一引数 : 画像情報
71 # 第二引数 : 輪郭を形成する画素(点)情報
72 # 第三引数 : 輪郭を形成する画素(点)のインデックス番号を指定する。例えば0を指定すると、1番目の輪郭を形成する画素(点)のみを描画する。1を指定すると、2番目の輪郭を形成する画素(点)のみを描画する。輪郭を形成する画素(点)を全て描画したい場合は、-1を指定する。
73 # 第四引数 : 輪郭を形成する画素(点)の色。
74 # 第五引数(任意) : 輪郭を形成する画素(点)の大きさを設定。デフォルト1。
75 # 戻り値 : 画像情報
76 # drawContoursについて : https://kuroro.blog/python/xaw33ckABzGLiHDFWC3m/
77 self.img = cv2.drawContours(self.img, self.contours, -1, 192, 5)
78
79 # 画像を保存する関数
80 def writeImg(self, filePath):
81 # imwrite : 画像の保存を行う関数
82 # imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
83 # 第一引数 : 保存先の画像ファイル名
84 # 第二引数 : 多次元配列(numpy.ndarray)
85 cv2.imwrite(filePath, self.img)
86
87# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
88# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
89# 第一引数 : 画像のファイルパス
90ins = Paint(cv2.imread('./xxx.xxx'))
91ins.setGray()
92ins.setBinaryImage()
93
94for type in [cv2.RETR_EXTERNAL, cv2.RETR_LIST, cv2.RETR_CCOMP, cv2.RETR_TREE]:
95 ins.exeFindContours(type)
96 ins.exeDrawContours()
97 ins.writeImg(str(type) + '.xxx')
以下の画像のように、第二引数(mode)へ与えるタイプによって、輪郭の検出に違いが現れます。
元画像
cv2.RETR_EXTERNAL
cv2.RETR_LIST
cv2.RETR_CCOMP
cv2.RETR_TREE
drawContoursに関しては、OpenCVで使われるdrawContoursって?具体的な活用法を徹底解説!?でまとめていますので、詳しく知りたい方は是非ご確認ください。
findContours関数の第三引数(method)で指定される、タイプについて調べてみた
findContours関数の第三引数(method)では、輪郭を形成する、画素(点)を近似する方法のタイプを指定します。
輪郭を形成する、画素(点)を近似する方法のタイプとしては、
タイプ名称 | 特徴 |
---|---|
cv2.CHAIN_APPROX_NONE | 輪郭を形成する、すべての画素(点)を利用します。 |
cv2.CHAIN_APPROX_SIMPLE | 輪郭を形成する画素(点)を、要所で必要な数だけ利用する。 |
cv2.CHAIN_APPROX_TC89_L1, cv2.CHAIN_APPROX_TC89_KCOS | Teh-Chinチェーン近似アルゴリズムの1つを適用します。 |
があります。
例えば以下のようなコードを作成すると、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4class Paint:
5 # 画像情報
6 img = None
7 # しきい値情報
8 # しきい値とは? : https://wa3.i-3-i.info/word15002.html
9 ret = None
10 # 輪郭を形成する画素(点)情報
11 contours = None
12 # オブジェクト(物体)の階層構造情報
13 hierarchy = None
14
15 # コンストラクタ
16 # コンストラクタとは? : https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF#:~:text=%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%EF%BC%88%E8%8B%B1%3A%20constructor%EF%BC%89%E3%81%AF,%E5%AF%BE%E7%BE%A9%E8%AA%9E%E3%81%AF%E3%83%87%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%80%82
17 # 画像の初期化
18 def __init__(self, image=None):
19 self.img = image
20
21 # 画像をグレースケールに設定する関数
22 # グレースケールとは? : https://www.shinkohsha.co.jp/blog/monochrome-shirokuro-grayscale/
23 def setGray(self):
24 # cvtColor : 画像の色空間(色)の変更を行う関数。
25 # cvtColorについて : https://kuroro.blog/python/7IFCPLA4DzV8nUTchKsb/
26 # 第一引数 : 多次元配列(numpy.ndarray)
27 # 第二引数 : 変更前の画像の色空間(色)と、変更後の画像の色空間(色)を示す定数を設定。
28 # cv2.COLOR_BGR2GRAY : BGR(Blue, Green, Red)形式の色空間(色)を持つ画像をグレースケール画像へ変更する。
29 self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
30
31 # グレースケール画像を二値画像へ変更する関数
32 def setBinaryImage(self):
33 # threshold : しきい値を用いて画像を二値画像へ変更する関数。
34 # thresholdについて : https://kuroro.blog/python/jofbNumJ9HtfTxnM8QHJ/
35
36 # 第一引数 : 多次元配列(numpy.ndarray)
37 # 第二引数 : しきい値。float型。
38
39 # 第三引数 : しきい値を超えた画素に対して、255を設定する。しきい値を超えていないものに関しては、0を与える。
40
41 # 第四引数 : 二値画像を判定する条件のタイプを指定する。
42 # cv2.THRESH_BINARY : (画素 <= 第二引数)の場合、画素に対して、0の値を与える。(画素 > 第二引数)の場合、画素に対して、第三引数の値を与える。
43
44 # 戻り値 #################
45 # self.ret : しきい値を返す。
46 # self.img : 多次元配列(numpy.ndarray)を返す。
47 #########################
48 self.ret, self.img = cv2.threshold(self.img, 160, 255, cv2.THRESH_BINARY)
49
50 # 輪郭の検出を行う関数
51 def exeFindContours(self, type):
52 # findContours : 輪郭の検出を行う関数
53 # 第一引数(thresh) : 二値画像情報
54 # 第二引数(mode) : 輪郭を検出するタイプを指定する。
55 # 第三引数(method) : 輪郭を形成する、画素(点)を近似する方法のタイプを指定する。
56 # 戻り値 ###########################################
57 # self.img : 輪郭付き画像情報
58 # self.contours : 輪郭を形成する画素(点)情報
59 # self.hierarchy : オブジェクト(物体)の階層構造情報
60 ####################################################
61
62 # OpenCVのバージョンが4.0より小さい場合
63 # self.img, self.contours, self.hierarchy = cv2.findContours(self.img, cv2.RETR_EXTERNAL, type)
64 # OpenCVのバージョンが4.0以上の場合
65 self.contours, self.hierarchy = cv2.findContours(self.img, cv2.RETR_EXTERNAL, type)
66
67 # 輪郭の描画を行う関数
68 def exeDrawContours(self):
69 # drawContours : 輪郭の検出情報をもとに、輪郭の描画を行う関数
70 # 第一引数 : 画像情報
71 # 第二引数 : 輪郭を形成する画素(点)情報
72 # 第三引数 : 輪郭を形成する画素(点)のインデックス番号を指定する。例えば0を指定すると、1番目の輪郭を形成する画素(点)のみを描画する。1を指定すると、2番目の輪郭を形成する画素(点)のみを描画する。輪郭を形成する画素(点)を全て描画したい場合は、-1を指定する。
73 # 第四引数 : 輪郭を形成する画素(点)の色。
74 # 第五引数(任意) : 輪郭を形成する画素(点)の大きさを設定。デフォルト1。
75 # 戻り値 : 画像情報
76 # drawContoursについて : https://kuroro.blog/python/xaw33ckABzGLiHDFWC3m/
77 self.img = cv2.drawContours(self.img, self.contours, -1, 192, 5)
78
79 # 画像を保存する関数
80 def writeImg(self, filePath):
81 # imwrite : 画像の保存を行う関数
82 # imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
83 # 第一引数 : 保存先の画像ファイル名
84 # 第二引数 : 多次元配列(numpy.ndarray)
85 cv2.imwrite(filePath, self.img)
86
87# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
88# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
89# 第一引数 : 画像のファイルパス
90ins = Paint(cv2.imread('./xxx.xxx'))
91ins.setGray()
92ins.setBinaryImage()
93
94for type in [cv2.CHAIN_APPROX_NONE, cv2.CHAIN_APPROX_SIMPLE, cv2.CHAIN_APPROX_TC89_L1, cv2.CHAIN_APPROX_TC89_KCOS]:
95 ins.exeFindContours(type)
96 ins.exeDrawContours()
97 ins.writeImg(str(type) + '.xxx')
以下の画像のように、第三引数(method)へ与えるタイプによって、輪郭を形成する、画素(点)を近似する方法に違いが現れます。
元画像
cv2.CHAIN_APPROX_NONE
cv2.CHAIN_APPROX_SIMPLE
cv2.CHAIN_APPROX_TC89_L1
cv2.CHAIN_APPROX_TC89_KCOS
まとめ
- OpenCVで使われるfindContoursとは、輪郭を検出して、画像内に含まれるオブジェクト(物体)を取得する関数を意味する。
- 「画像のどの部分を輪郭として検出すべきか」判定できるように、二値画像へ加工する前処理を行う必要がある。
参考文献
- OpenCVで使われるfindContours関数に関するサンプルコード
- 画素とは?
- 二値画像とは?
- インタラクティブモードとは?
- グレースケールとは?
- 階層構造とは?
- コンストラクタとは?
- しきい値とは?
- 画像の色を変更するタイプ一覧情報
- 二値画像を判定する条件のタイプ一覧情報