この記事で、OpenCVで輪郭抽出・検出する方法を解説しています。
便利な関数がOpenCVには用意されています。
本記事の内容
- OpenCVで輪郭抽出する環境
- 【輪郭検出関数】findContours
- 画像をグレースケール化する
- findContoursで輪郭抽出を行う
- 【結論】findContoursに過剰に期待するのはやめておきましょう
それでは、上記に沿って解説していきます。
OpenCVで輪郭抽出する環境
OpenCVは、いろいろな環境で動きます。
いわゆるクロスプラットフォームというモノですね。
対応OS
- Windows
- Linux
- FreeBSD
- macOS
- Android
- iOS
対応言語
- C/C++
- Java
- Python
この記事では、Windows上のPythonで検証を行います。
OenCVのインストールに関しては、次の記事をご覧ください。
準備が整ったら、実際にOpenCVで輪郭検出を行っていきましょう。
【輪郭検出関数】findContours
冒頭で述べたように、OpenCVには便利な関数が用意されています。
findContours
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
引数
image | 8ビット,シングルチャンネル(グレースケール) |
mode | 輪郭検索モード |
method | 輪郭近似法 |
offset | すべての輪郭点をシフトさせるオフセット |
戻り値
contours | 検出された輪郭の座標(配列) |
hierarchy | 検出された輪郭毎の階層構造情報(配列) |
正直、説明を見てもよくわからないと思います。
実際に使っているところを確認しましょう。
ただ、imageのグレースケールには注意ですね。
用意する画像は、グレースケールで読み込んでおく必要があります。
輪郭抽出の前に、画像をグレースケール化することをプログラムで確認しておきましょう。
画像をグレースケール化する
対象画像は、わかりやすいモノとして以下を用意。
test.png
この画像をグレースケール化します。
そのためのプログラムコードは以下。
import cv2 # 画像読み込み img = cv2.imread("./img/test.png") # グレースケール化 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 画像保存 cv2.imwrite("./img/test_gray.png", img_gray)
imgフォルダにあるtest.pngを読み込みます。
読み込んだ画像をグレースケール化。
そして、グレースケール化した画像をファイルに保存。
このプログラムを実行すると、次の画像が作成できました。
test_gray.png
見事にグレースケール化されています。
グレースケール化に関しても理解できたので、輪郭抽出を検証します。
findContoursで輪郭抽出を行う
最初に、輪郭抽出した画像を表示します。
test_contours.png
上手く輪郭抽出できていますね。
ただし、ここまでやるのに苦労しました。
苦労したコードは、以下。
import cv2 # 画像読み込み img = cv2.imread("./img/test.png") # グレースケール化 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_gray = cv2.GaussianBlur(img_gray, (7, 7), 0) img_gray= cv2.medianBlur(img_gray, 1) # 輪郭を抽出する ret,thresh = cv2.threshold(img_gray, 230, 255,0) contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) # 読み込んだ画像に輪郭を描画 img_contours = cv2.drawContours(img, contours, -1, (225, 0 ,225), 3) # 輪郭を描画した画像をファイルに保存 cv2.imwrite("./img/test_contours.png", img_contours)
見てウンザリしますよね。
メソッドがたくさん出てきます。
各メソッドのパラメータを試行錯誤して調整しました。
それが上記の結果です。
最後に、今回の記事のまとめをしておきます。
【結論】findContoursに過剰に期待するのはやめておきましょう
結論は、そのままです。
「findContoursに過剰に期待はするな」です。
私は、findContoursにはもっと期待していました。
画像を読み込ませれば、さくっと輪郭抽出ができるモノだと。
しかし、現実はそんなに甘くありませんでした。
まずは、その現実を一緒に確認しましょう。
別の画像を読み込むと、途端に上記コードは動きません。
例えば、以下の画像です。
読み込み画像
輪郭抽出した画像
全く機能していません。
おそらく、各メソッドのパラメータを調整すれば、輪郭抽出をすることでしょう。
しかし、画像毎にパラメータを調整するのはやってられません。
バカらしいです。
もちろん、私のコードがよろしくないのは理解しています。
もっといいコーディングはあるのかもしれません。
そうだとしても、findContoursには期待過剰でした。
正確には、findContoursはちゃんと仕事をしているのかもしれません。
ただ、findContoursに渡す画像を用意するのが、あまりも大変です。
それもひっくるめてfindContoursには、期待を裏切られました。
利用する状況次第なのでしょうね、その効果は。
もし、この記事を読んでfindContoursを弁護する方がいれば、是非とも意見をお願いします。
問い合わせフォームからでも、Twitterからでもお願いします。