質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

24404閲覧

OpenCVで切れてしまっている輪郭を抽出したい

acre_maker

総合スコア145

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/09/20 12:45

編集2018/09/20 13:06

前提・実現したいこと

OpenCVにてcv2.findContours()を用いて輪郭をしようと試みていますがデータによっては肝心の輪郭が切れてしまっています。
そのような場合でもうまく輪郭を抽出する方法はありますでしょうか?

試したこと

cv2.canny()によってエッジ検出を行なった画像に対してcv2.findContours()を行なっています。
cv2.GaussianBlur()のぼかし、cv2.dilate()による膨張などを前処理としてやってみましたがダメでした。
凸包を用いたら良いのかなと思いましたが引数のデータ点をまずどうやって手に入れるかを今度は検討する必要がありますでしょうか?

ご指導ご鞭撻のほどよろしくお願いします。

追記
実際の画像は持ち出せないためお見せすることができないので申し訳ないですがイメージしてはこのような図です。
背景は完全ではありませんが白色に近いです。
水滴のようにマルのような形になることが多いです。
うまくいく画像もあるのですが失敗しているものは外からの強い光の関係で輪郭が消えてしまっているようです。
コントラストを上げたり下げたりしてみましたが残念ながらうまくいきませんでした。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2018/09/20 12:52

画像を貼ることは可能ですか。どのような画像かを見ないと手法の提案は難しいです。
acre_maker

2018/09/20 13:06

ありがとうございます。わかりづらいとは思いますがイメージ図をのせてみました。いかがでしょうか?
fana

2018/09/21 02:10

「強い光の関係で輪郭が消えてしまっている」というのが,(1)画素値の差が少なくなっている(が,輪郭は画素値の差としては存在している)なのか,それとも,(2)完全に白飛びのような状態で画素値からは輪郭の存在が見つけられない なのか,どちらでしょう?(あるいは,両方有り得る?)
acre_maker

2018/09/21 20:37

(1)のほうですね!目視ではうっすら確認できます。
fana

2018/09/22 06:55

雑音に埋もれない程度の強度でエッジが存在しているのであれば,コントラストを改善することでcannyでひっかけやすくなるとは思います.既にadaptiveThreshold()が回答で挙げられていますが,そのような「画像全体への一括処理ではない」方法でコントラストの改善を行うと良いのではないでしょうか.
acre_maker

2018/09/23 09:14

ありがとうございます。局所的にコントラストを最適化するcv2.createCLAHEを試してみますね!
guest

回答3

0

イメージ図のように,

  • 対象形状がシンプル(マルに近い)
  • 必要な輪郭がそれなりには取得できている
  • 必要ない輪郭(ゴミ)は除去できている

という状態まで行きつけるのであれば,
取得できている輪郭を単純に接続すればまずは一つながりのデータが作れるのではないでしょうか.

例えば,取得できている輪郭画素群の位置の重心から見た各画素位置の角度みたいなので,輪郭画素群に順序をつけることができれば,切れている箇所を「接続」することは可能.
最も単純には直線でつなげばとりあえずは補間完了ですし,もうちょっと頑張るならスプラインとかで補間してもよいでしょう.
(必要ならば,切れている距離とか,切れている部分のエッジ線の向きの差とかを見て,諦める判断をしてもいい)

で,輪郭が切れていた箇所にも絵的にはそれなりに輪郭(輝度差)が見えるのであれば,後段処理にSnake法みたいな手段を用いれば,補間した箇所を絵に合う形にRefinementすることもできるかもしれません.
(逆に,輪郭が切れている箇所がデータとして「完全に見えない」ならば,画素値を用いる手段をいくら頑張っても無理なので,前記スプライン的な方法で「それっぽい形」に繋ぐくらいしかないんじゃないかと)

投稿2018/09/21 03:10

編集2018/09/21 03:14
fana

総合スコア11632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

acre_maker

2018/09/23 09:17 編集

Snake法という手法初耳なので勉強になりました。いろいろ勉強してどうするか検討してみますね! ありがとうございました!
guest

0

ベストアンサー

cv2.findContours() は連結している非零のピクセルをなぞり、輪郭を見つけるだけなので、少しでも隙間があると別々の輪郭であると判定されてしまいます。

cv2.findContours() の結果を改善するには、その前段階できれいな2値画像を作成する必要があります。

  • Canny() を使うなら、ヒステリシスの閾値 threshold1、threshold2 の最適なパラメータの値を探す。

閾値の意味は、こちら を参照

  • モルフォロジー変換 で前処理を頑張る。cv2.dilate() を試されたようですが、他にもあります。
  • 2値化を Canny() ではなく、threashold()、inRange()、adaptiveThreshold() 等で行う。

抽出したい対象物がだいたい同じ色をしている等であれば、閾値処理の2値化のほうが安定します。

  • 輪郭抽出対象が画像ごとに異なる: Canny()
  • 輪郭抽出対象が画像ごとにほぼ同じ: threashold()、inRange()、adaptiveThreshold()

投稿2018/09/20 15:36

編集2018/09/20 15:39
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

acre_maker

2018/09/23 09:16

Cannyとその他のそれぞれの手法の使い分けありがとうございます!参考にさせていただきます。 inRangeやadaptiveThresholdでテスト画像6枚のうち4枚は認識するようになりました。 残りももう少し頑張って無理そうなら別途どうするか検討しますね。
guest

0

OpenCVもPythonも十分に使えて無いので、具体的なコードを提示できませんが、
(演習問題でやってみたいのですが、すぐは無理)

イメージ図みたいに明確な形状が抽出できているならば、端点リストを作って近傍の端点を連結するのはどうでしょうか?
どの範囲まで近傍と見なすか、検討が必要なのと、連結後の図形が希望するものかの検証が必要です。

(今、CAD図面を元に隙間のある線分の連結処理を行っています。OpenCVも使っているが、別の目的なので、OpenCVでの方法の確認はしてません)

投稿2018/09/20 13:39

pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問