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

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

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

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

Python

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

Q&A

受付中

OpenCVで楕円形のオブジェクトを認識したい。

Sakana4432
tajama3

総合スコア4

OpenCV

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

Python

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

3回答

0グッド

1クリップ

295閲覧

投稿2022/12/02 09:03

編集2022/12/02 09:06

OpenCVを使い、画像から白色の楕円型オブジェクトを切り抜くプログラムを考えています。

楕円オブジェクトの検出はほかのプログラムで行い、ここでは楕円オブジェクトの輪郭の切り抜きだけを行います。
HSVで画像を読み込んだ後、処理を重ねて大まかな輪郭を取得することはできましたが、光の反射等の映り込みにより、きれいな形を切り抜くことができません。

写真1枚目が加工なしの輪郭。
2枚目がapproxPolyDPをかけたあとの輪郭。
3枚目の赤い部分が不要な箇所です。

写真からわかるように本体から突出した部分だけ削除する方法を考えています。
何かアドバイスを頂けないでしょうか。
よろしくお願いいたします。

イメージ説明

イメージ説明

イメージ説明

Python

1import cv2 2import numpy as np 3 4img= cv2.imread("image.jpg") 5img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) 6 7#検出範囲(HSV) 8white_min = (22,0,178) 9white_max = (210,51,255) 10 11img = cv2.inRange(img, white_min, white_max) 12 13#HSV範囲内で最大の輪郭を取得 14contours = cv2.findContours( 15 img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] 16 17max_cnt = max(contours, key=lambda x: cv2.contourArea(x)) 18 19#表面の凹凸を減らす 20max_cnt = cv2.approxPolyDP(max_cnt, epsilon=0.001 *cv2.arcLength(max_cnt, True), closed=True) 21 22out = np.zeros_like(img) 23cv2.drawContours(out,[max_cnt], -1, color=255, thickness=-1)

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

fourteenlength

2022/12/02 10:55

自身がないのでこちらで。 方法1.巨大なカーネルを使ってOpening処理 http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html#opening 方法2.巨大なガウシアンカーネルを使ってぼかし、閾値処理で白い場所をくくりだす http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_filtering/py_filtering.html#id5 ぼけきっていない値の高い場所(たとえば200以上)などを選定すればそれっぽく括りだせるかも?
fana

2022/12/02 11:18

> 方法2.巨大なガウシアンカーネルを使ってぼかし、閾値処理で白い場所をくくりだす 私の過去の質問↓でやってるような感じですかね. https://teratail.com/questions/204418
Sakana4432

2022/12/02 13:11

お返事ありがとうございます。 opening処理を行ったところ、かなり角が取れて理想に近い形になりました。 必要な部分も削れてしまいましたが、あとは値の調整で上手く仕上げようと思います。 ありがとうございました。
jbpb0

2022/12/26 10:16

> opening処理を行ったところ、かなり角が取れて理想に近い形になりました。 解決したのなら、「解決済」にしてください

回答3

1

fourteenlength 氏の既存回答の「やせた身」を得る処理を OpenCV に存在する関数でやるとしたら,
distanceTransform() の結果に適当な閾値を適用する感じかな.

C++

1int main() 2{ 3 cv::Mat Img = cv::imread( "imo.png", cv::IMREAD_GRAYSCALE ); 4 if( Img.empty() )return 0; 5 cv::threshold( Img, Img, 128, 255, cv::THRESH_BINARY ); //※念のため 6 7 cv::Mat Mask; 8 {//「やせた身」を作る 9 cv::Mat Dist; 10 cv::distanceTransform( Img, Dist, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32F ); 11 12 cv::Mat Th; 13 cv::threshold( Dist, Th, 10, 255, cv::THRESH_BINARY ); 14 Th.convertTo( Mask, CV_8U ); 15 } 16 17 //てきとーに太らせて使う 18 cv::dilate( Mask, Mask, cv::Mat(), cv::Point(-1,-1), 9 ); 19 cv::bitwise_and( Img, Mask, Mask ); 20 Img.setTo( 128, Mask ); 21 22 cv::imshow( "Img", Img ); 23 cv::waitKey(); 24 return 0; 25}

結果:
イメージ説明

投稿2022/12/05 03:55

fana

総合スコア10672

fourteenlength👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

fana

2022/12/06 02:14

処理の意味的には,身を太らせる dilate での構造要素は円形な感じたるべきかな,とか思ったりするけど,そこらへんはまぁいいようにやっていただくということで.

0

別の方法も思い出したので参考までに。

成果物
イメージ説明

スケルトン

Scikit-imageという、顕微鏡で観察した結果などをイイ感じに加工するライブラリがあります。そこにスケルトンというのがあり、二値化画像の「骨」を抽出できます。

イメージ説明
スケルトンの身を探る

が、スケルトンだと本当に骨しか出てこず、ほしいものとちょっと違います。本当は「身」がほしいので、ここから身を取り出す関数を使います。具体的には、thin()という関数です。
※thinは先のスケルトンと同じチュートリアルのURLで紹介されていますのでURLは省略します。
イメージ説明

余分な骨を消す

ここで、thinで身を取り出せましたが、残った骨が邪魔になりました。残った骨はOpenCVのモルフォロジーのopen()で片づけます。

加工後生画像
イメージ説明イメージ説明

※元画像と比べると分かりやすいですが、このままではやせすぎています。

やせ過ぎた分太らせる

先のOpenCVの別の関数、モルフォロジーのdilate()で片づけます。

太らせた後やせたまま生画像
イメージ説明イメージ説明イメージ説明

という感じです。

「どれだけ元画像からゴミを取り除いた/取り除きすぎたんだ?」という疑問をお持ちの方は、一番上の画像を参照ください。まぁこれが妥協点だろう、と思っていただけるのではないでしょうか?

課題

枝葉のように生えた部分の大きさやskeletonのiterによっては、枝葉の部分と本体とに分割されます。こういったときには、以下のような感じで処理すると良いと思います。

  1. iterを機械学習でいうハイパーパラメータとして割り切って適当にやり過ごす
  2. それでも何とかなるようにblob検出をして一番大きい本体だけに注目する
import sys import os import numpy as np import cv2 from skimage.morphology import skeletonize, thin # グレースケールとして読み込み img_path = os.path.split(os.path.abspath(__file__))[0] + "/img.png" img_raw = cv2.imread(img_path,0) cv2.imshow("img_raw",img_raw) # skimage用に二値化 _,img = cv2.threshold(img_raw ,127,255,cv2.THRESH_BINARY) img[0 < img] = 1 # # スケルトン # # https://scikit-image.org/docs/stable/auto_examples/edges/plot_skeleton.html # img_skeleton= skeletonize(img).astype(np.uint8) # img_skeleton[0<img_skeleton] = 255 # cv2.imshow("img_skeleton",img_skeleton) # cv2.imwrite("img_skeleton.png",img_skeleton) # スケルトン(塗りつぶし) iter = 5 # img_thin = thin(img, max_num_iter=iter).astype(np.uint8) # <--チュートリアルに沿った表記 img_thin = thin(img, max_iter=iter).astype(np.uint8) # <--手元のskimageはこれでないと動かない img_thin[0<img_thin] = 255 cv2.imshow("img_thin",img_thin ) # cv2.imwrite("img_thin.png",img_thin) # スケルトン(塗りつぶし)にモルフォロジー(オープニング) kernel = np.ones((3,3),np.uint8) #可能な限り小さいカーネルでスケルトンの余分なところを潰す img_thin_opened = cv2.morphologyEx(img_thin, cv2.MORPH_OPEN, kernel) cv2.imshow("img_thin_opened",img_thin_opened) # cv2.imwrite("img_thin_opened.png",img_thin_opened) # やせた分太らせる img_thin_opened_dil = cv2.dilate(img_thin_opened ,kernel,iterations = 4) # cv2.imwrite("img_thin_opened_dil.png",img_thin_opened_dil) # 差分を出す img_diff = img_raw.copy() img_diff[img_thin_opened_dil ==255] = 128 cv2.imshow("img_diff",img_diff) # cv2.imwrite("img_diff.png",img_diff) cv2.waitKey(0)

投稿2022/12/03 01:18

編集2022/12/03 01:22
fourteenlength

総合スコア2748

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

0

残るべき対象形状がある程度「楕円」と呼べる形じゃないと機能しないと思いますが,

領域の輪郭データにとりあえず楕円当てはめを行ってしまえばどうでしょうか.
ただし, OpenCVの fitEllipse() 系の関数を使うのではなくて,RANSAC みたいなロバスト推定な処理を用いる
そうすれば,突起物に引っ張られずに芋っぽい部分に対する当てはめになるかな,と.

で,その結果の楕円から外側に出ている部分を除去する感じの方向で.
※本当に楕円の輪郭でばっさり切ってしまうのではなく,ある程度の距離までは許容するとか,そこらへんの検討/調整は要るかもですが,それで明らかに突起物な箇所を捨てられるのではないかな,と.
(モルフォロジとかぼかしみたいなのは,これ以降の後段処理として用いれば,でかいカーネルサイズを用いずに済むんじゃないかな)

投稿2022/12/02 11:31

編集2022/12/02 11:32
fana

総合スコア10672

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

fana

2022/12/02 11:34

> 芋っぽい 画像例の形が,放置しすぎて芽が生えたじゃがいも に見えた.
Sakana4432

2022/12/02 13:13

お返事ありがとうございます。 確かに芋が芽吹いているようにも見えますね。 おかげさまで芽の除去に成功しそうです。 ありがとうございました。

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

OpenCV

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

Python

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